///////////////////////////////////////////////////////////////////////////////
/// @file deXLoader.cpp
///
/// @brief Ability to load up DirectX X files
///
/// @author Assassin
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Mar 2003
/// @author Assassin
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

// some functions contained within adapted from articles on 
// gamedev.net and http://64.33.37.114/loadxfiles.html

#ifndef DESTINY3D_EXPORT_ALL
#define XLOADER_DEPRECATED
#endif

#ifdef XLOADER_DEPRECATED
#include "deBrush.hpp"
#include "deMesh.hpp"
deBoolean IdeBrush_LoadFromXFile(const char * /*filename*/, deTList<IdeStaticBrush*> & /*brushplist*/)
{
	DEBUGRETURN(deFALSE,"IdeBrush_LoadFromXFile() has been deprecated");
}
deBoolean IdeBrush_LoadLargeStaticeFromXFile(const char * /*filename*/, IdeLargeStaticBrush* /*pBrush*/, const deTransformInfo * /*XForm*/)
{
	DEBUGRETURN(deFALSE,"IdeBrush_LoadLargeStaticeFromXFile() has been deprecated");
}
deBoolean IdeMesh_LoadStaticFromXFile(const char * /*filename*/, IdeMesh* /*pMesh*/, const deTransformInfo * /*Transform*/)
{
	DEBUGRETURN(deFALSE,"IdeMesh_LoadStaticFromXFile() has been deprecated");
}
#else //XLOADER_DEPRECATED

#define LEAK_HUNTING

#include "deXLoader.hpp"

#include <rmxftmpl.h>
#include <rmxfguid.h>
#include <d3dx8math.h>

#include "deList.hpp"
#include "deBrush_priv.hpp"
#include "deBitmap.hpp"
#include "deMesh.hpp"
#include "deString.hpp"
#include "deSurface.hpp"

#pragma comment (lib, "d3dx8")
#pragma comment (lib, "D3dxof")
#pragma comment (lib, "dxguid")
#pragma comment (lib, "advapi32")

#ifndef NULL
#define NULL (0)
#endif

#define ReleaseCOM(x) if(!x){}else x->Release()
#define NUMTEXTURES (1024)

DWORD deXNumTextures;
deXTexture deXTextureList[NUMTEXTURES];

void WipeGlobals()
{
	deXNumTextures = 0;
	int i;
	for (i = 0; i < NUMTEXTURES; i++)
	{
		deXTextureList[i].Texture_Name[0] = '\0';
		deXTextureList[i].RenderTexture = NULL;
	}
}

deXMesh::deXMesh()
{
	NumVerts = 0;
	NumIndices = 0;
	VertList = NULL;
	NormList = NULL;
	CoordList = NULL;
	MaterialList = NULL;
	Child = NULL;
	Next = NULL;
	Indices = NULL;

	HasVerts = deFALSE;
	HasNorms = deFALSE;
	HasCoords= deFALSE;

	D3DXMATRIX mat;
	D3DXMatrixIdentity(&mat);
	Matrix = mat;
}

#define SafeDelete(x) if(!x){}else delete x
#define SafeDeleteArr(x) if(!x){}else delete[] x
deXMesh::~deXMesh()
{
	DWORD k;
	if (MaterialList)
	{
		for (k = 0; k < NumMaterials; ++k)
		{
			if (MaterialList[k].deMat)
				MaterialList[k].deMat->Release();
		}
	}
	SafeDelete (Next);
	SafeDelete (Child);
	SafeDelete (Indices);
	SafeDeleteArr (VertList);
	SafeDeleteArr (NormList);
	SafeDeleteArr (CoordList);
	SafeDeleteArr (MaterialList);
}

void deXMesh::AddChild(deXMesh *pChildObject)
{
	if (Child!=NULL)
	{
		Child->AddNext(pChildObject);
	}
	else
	{
		Child=pChildObject;
	}
}

void deXMesh::AddNext (deXMesh *pChildObject)
{
	if (Next!=NULL)
		Next->AddNext (pChildObject);
	else
		Next=pChildObject;
}

void deXMesh::GenerateNormals()
{
	D3DXVECTOR3 *Normals = new D3DXVECTOR3[NumVerts];
	ZeroMemory(Normals, sizeof(D3DXVECTOR3)*NumVerts);
	
	DWORD NumIndices=0;
	DWORD i;
	for (i=0;i<NumMaterials;i++)
	{
		NumIndices+=MaterialList[i].NumIndices;
	}
	WORD p1;
	WORD p2;
	WORD p3;
	D3DXVECTOR3 v1;
	D3DXVECTOR3 v2;
	D3DXVECTOR3 * v3;
	D3DXVECTOR3 n, temp;
	for (i=0;i<NumIndices;i+=3)
	{
		p1=Indices[i];
		p2=Indices[i+1];
		p3=Indices[i+2];
		v1=VertList[p1];
		v2=VertList[p2];
		v3=(D3DXVECTOR3*) &VertList[p3];
		
		D3DXVec3Subtract(&temp, &v2, &v1);
		D3DXVec3Subtract(&v1, v3, &v2);
		D3DXVec3Cross(&v2, &temp, &v1);
		D3DXVec3Normalize(&n, &v2);

		Normals[p1] += n;
		Normals[p2] += n;
		Normals[p3] += n;
	}

	for (i=0;i<NumVerts;i++)
	{
		D3DXVec3Normalize(&temp, &(Normals[i]));
		NormList[i].x = temp.x;
		NormList[i].y = temp.y;
		NormList[i].z = temp.z;
	}

	delete Normals;
}

void GetMesh (LPDIRECTXFILEDATA pMeshData, deXMesh * Parent);
void GetMaterial (deXMesh *Mesh, LPDIRECTXFILEDATA pMaterialData, DWORD Material_Index);
void GetFrame(LPDIRECTXFILEDATA pFrameData, deXMesh *Parent);

deXMesh * deXLoader_LoadX(const char * filename)
{
	IDirectXFile			*pDXFile = NULL;
	IDirectXFileEnumObject	*pDXEnum = NULL;
	IDirectXFileData		*pDXData = NULL;
	const GUID				*pGuid;
	deXMesh					*Object_Root=NULL;
//	char					*tempstr=NULL;

	WipeGlobals();

	// Create the .X file object
	if(FAILED(DirectXFileCreate(&pDXFile)))
		return NULL;

	// Register the templates in use
	// Use the standard retained mode templates from Direct3D
	if(FAILED(pDXFile->RegisterTemplates((LPVOID)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
	{
		ReleaseCOM(pDXFile);
		return FALSE;
	}

//	tempstr = new char[strlen(filename)+1];
//	strcpy(tempstr, filename);
	if (SUCCEEDED(pDXFile->CreateEnumObject((void*)filename, DXFILELOAD_FROMFILE, &pDXEnum)))
	{
		Object_Root = new deXMesh();

		while (SUCCEEDED(pDXEnum->GetNextDataObject(&pDXData)))
		{
			pDXData->GetType(&pGuid);
			if (*pGuid==TID_D3DRMMesh)
				GetMesh (pDXData,Object_Root);
			if (*pGuid==TID_D3DRMFrame)
				GetFrame (pDXData,Object_Root);
			ReleaseCOM(pDXData);
		}
		ReleaseCOM(pDXEnum);
	}

	ReleaseCOM(pDXFile);
	return Object_Root;
}

void GetMesh (LPDIRECTXFILEDATA pMeshData, deXMesh * Parent)
{
	LONG DataPointer;
	DWORD Size;
	LPDIRECTXFILEOBJECT pChild_Object;
	D3DVECTOR *pVectors;
	WORD loop;

	// get the actual mesh data

	pMeshData->GetData(NULL,&Size, (VOID **) &DataPointer);

	// create a new mesh and retireve ythe vertex count

	deXMesh * NewMesh = new deXMesh();
	NewMesh->NumVerts = *((DWORD*)DataPointer);
	DataPointer += 4;

	// fill in the vertex array of the new object

	pVectors = (D3DVECTOR *)DataPointer;
	NewMesh->VertList = new D3DVECTOR [NewMesh->NumVerts];
	NewMesh->NormList = new D3DVECTOR [NewMesh->NumVerts];
	NewMesh->CoordList= new deXTexCoord [NewMesh->NumVerts];
	ZeroMemory(NewMesh->VertList, sizeof(D3DVECTOR)*NewMesh->NumVerts);
	ZeroMemory(NewMesh->NormList, sizeof(D3DVECTOR)*NewMesh->NumVerts);
	ZeroMemory(NewMesh->CoordList,sizeof(deXTexCoord)*NewMesh->NumVerts);
	for (loop = 0; loop < NewMesh->NumVerts; loop++)
	{
		NewMesh->VertList[loop].x = pVectors[loop].x;
		NewMesh->VertList[loop].y = pVectors[loop].y;
		NewMesh->VertList[loop].z = pVectors[loop].z;
	}

	DataPointer += (sizeof(D3DVECTOR))*(NewMesh->NumVerts);

	// now retieve the face count
	DWORD NumFaces = *((DWORD *)DataPointer);
	DataPointer+=4;
	DWORD * face_list = (DWORD *)DataPointer;

	//find out how much storage space we will need to store indices after triangle conversion
	{
		DWORD Number_Of_faces = NumFaces;
		NewMesh->NumIndices = 0;
		while (Number_Of_faces-- > 0 )
		{
			NewMesh->NumIndices += (*face_list - 2) * 3;
			face_list += *face_list + 1;
		}
		NewMesh->Indices = new WORD[NewMesh->NumIndices];
		face_list = (DWORD *)DataPointer; 
	}
//	NewMesh->NumIndices = NumFaces * 3;
//	NewMesh->Indices = new WORD [NewMesh->NumIndices];

	// Lets find out which index goes with which material
	while (SUCCEEDED (pMeshData->GetNextObject( &pChild_Object)))
	{
		LPDIRECTXFILEDATA pChild_Data;
			
		if (SUCCEEDED(pChild_Object->QueryInterface (IID_IDirectXFileData,(VOID **)&pChild_Data)))
		{
			const GUID *pGuid;
			LONG pDataBlock;
			DWORD dwSize;

			pChild_Data->GetType(&pGuid);
			pChild_Data->GetData(NULL,&dwSize,(VOID **) &pDataBlock);

			if (*pGuid == TID_D3DRMMeshMaterialList)
			{
				NewMesh->NumMaterials = *((DWORD*)pDataBlock);
				pDataBlock += 4;
				DWORD Number_Of_MatFaces = *((DWORD*)pDataBlock);
				pDataBlock += 4;
				DWORD * pMaterial_Faces = (DWORD*)(pDataBlock);

				// reserve the number of materials in thr material list
				NewMesh->MaterialList = new deXMaterial[NewMesh->NumMaterials];
				WORD * pindices = NewMesh->Indices;
				ZeroMemory(NewMesh->MaterialList, sizeof(deXMaterial)*NewMesh->NumMaterials);

				// add the indices to the Indices pointer and split n sided faces
				if (NewMesh->NumMaterials == 1 || Number_Of_MatFaces != NumFaces)
				{
					DWORD facecount;
					WORD vertex1,vertex2,vertex3;
					DWORD verts_in_face;
					for (facecount = 0; facecount < NumFaces; facecount++)
					{
						verts_in_face = *face_list++;

						if (verts_in_face == 3)
						{
							vertex1 = (WORD)(*face_list++);
							vertex2 = (WORD)(*face_list++);
							*pindices++ = (WORD)(*face_list++);
							*pindices++ = vertex2;
							*pindices++ = vertex1;
							NewMesh->MaterialList[0].NumIndices += 3;
						}
						else if (verts_in_face > 3)
						{
							vertex1 = (WORD)(*face_list++);
							vertex2 = (WORD)(*face_list++);
							for (DWORD loop=2;loop<verts_in_face;loop++)
							{
								vertex3 = (WORD)(*face_list++);
								NewMesh->MaterialList[0].NumIndices += 3;
								// reversing face winding
								*pindices++ = vertex3;
								*pindices++ = vertex2;
								*pindices++ = vertex1;
								
								vertex2 = vertex3;
							}
						}
						else //if (verts_in_face < 3)
						{
							DE_ASSERT(verts_in_face >= 3);
						}
					}
				}// end if only one mat	
				else
				{
					DWORD *backup = face_list;
					DWORD mat;
					for (mat = 0; mat < NewMesh->NumMaterials; mat++)
					{// loop through each material
						face_list = backup;
						DWORD face;
						for (face=0;face<Number_Of_MatFaces;face++)
						{
							if (pMaterial_Faces[face]==mat)
							{
								// this face belongs with this material so increase the materials number and breakinto multiple triangles
								WORD vertex1,vertex2,vertex3;
								DWORD verts_in_face = *((DWORD*)face_list++);

								if (verts_in_face >= 2)
								{
									vertex1 = (WORD)(*face_list++);
									vertex2 = (WORD)(*face_list++);
									for (DWORD loop = 2; loop < verts_in_face; loop++)
									{
										vertex3 = (WORD)(*face_list++);
										NewMesh->MaterialList[mat].NumIndices += 3;
										// reversing face winding
										*pindices++ = vertex3;
										*pindices++ = vertex2;
										*pindices++ = vertex1;
										
										vertex2 = vertex3;
									}
								}
							}
						else
						{
							face_list+=(*face_list)+1;
						}
						}
					}// end loop through each material for mat=
					// now we are going to read in the actual Material Data
				}//end if multiple material faces

				LPDIRECTXFILEOBJECT pChildMaterialObject;
				DWORD CurrentMaterial=0;

				while (SUCCEEDED(pChild_Data->GetNextObject(&pChildMaterialObject)))
				{
				
					LPDIRECTXFILEDATA pMaterialData;
					LPDIRECTXFILEDATAREFERENCE pMaterialReference;

					if (SUCCEEDED (pChildMaterialObject->QueryInterface(IID_IDirectXFileData,(VOID **)&pMaterialData)))
					{
						const GUID * pGuid;
						pMaterialData->GetType(&pGuid);
						if (*pGuid == TID_D3DRMMaterial)
						{
							GetMaterial(NewMesh, pMaterialData, CurrentMaterial);
							CurrentMaterial++;
						}
						ReleaseCOM(pMaterialData);
					}

					if (SUCCEEDED (pChildMaterialObject->QueryInterface(IID_IDirectXFileDataReference, (VOID **) &pMaterialReference)))
					{
						if (SUCCEEDED (pMaterialReference->Resolve(&pMaterialData)))
						{
							const GUID * pGuid;
							pMaterialData->GetType(&pGuid);
							if (*pGuid == TID_D3DRMMaterial)
							{
								GetMaterial(NewMesh, pMaterialData, CurrentMaterial);
								CurrentMaterial++;
							}
							ReleaseCOM(pMaterialData);
						}
						ReleaseCOM(pMaterialReference);
					}
					
					ReleaseCOM(pChildMaterialObject);
				}// end while theres a child object
			}// end if this is a material list
			else if (*pGuid == TID_D3DRMMeshNormals)
			{
				DWORD numnorms = *((DWORD *)pDataBlock);
				D3DVECTOR * normals=(D3DVECTOR *)(pDataBlock+4);
				
				if (numnorms == NewMesh->NumVerts)// then each normal is a vertex normal
				{
					for (WORD a=0; a < numnorms; a++)
					{
						NewMesh->NormList[a].x=normals[a].x;
						NewMesh->NormList[a].y=normals[a].y;
						NewMesh->NormList[a].z=normals[a].z;
					}
					NewMesh->HasNorms = true;
				}

			}
			else if (*pGuid == TID_D3DRMMeshTextureCoords)
			{
				DWORD numcoords = *(DWORD*)pDataBlock;
				pDataBlock += 4;
				float *pointer = (float *)pDataBlock;
				for (WORD a=0; a < numcoords; a++)
				{
					NewMesh->CoordList[a].u = pointer[2*a+0];
					NewMesh->CoordList[a].v = pointer[2*a+1];
				}
				NewMesh->HasCoords = true;
			}
			ReleaseCOM(pChild_Data);
		}

		ReleaseCOM(pChild_Object);
	}

	NewMesh->HasVerts = true;

	if (NewMesh->HasNorms == false)
	{
		NewMesh->GenerateNormals();
		NewMesh->HasNorms = true;
	}

	Parent->AddChild(NewMesh);
}

void GetMaterial (deXMesh *Mesh, LPDIRECTXFILEDATA pMaterialData, DWORD Material_Index)
{
	LONG pData;
	DWORD dwSize;

	pMaterialData->GetData(NULL,&dwSize,(VOID **) &pData);
	IdeRenderMaterial::MatData mat;
	ZeroMemory(&mat,sizeof (D3DMATERIAL8));
	memcpy(&mat.DiffuseColor, (VOID*)(pData), sizeof(FLOAT)*4);
	memcpy(&mat.AmbientColor, (VOID*)(pData), sizeof(FLOAT)*4);
	memcpy(&mat.Power, (VOID*)(pData+16), sizeof(FLOAT)*1);
	memcpy(&mat.SpecularColor, (VOID*)(pData+20), sizeof(FLOAT)*3);
	memcpy(&mat.EmissiveColor, (VOID*)(pData+32), sizeof(FLOAT)*3);
// HACK
	mat.EmissiveColor.r = 0.5;
	mat.EmissiveColor.g = 0.5;
	mat.EmissiveColor.b = 0.5;
//	memcpy(&Mesh->MaterialList[Material_Index].Mat8, &mat, sizeof(D3DMATERIAL8));
	IdeRenderMaterial* deMat = IdeRenderState_CreateRenderMaterial();
	if (deMat && deMat->Lock())
	{
		deMat->SetAllData(&mat);
		deMat->Unlock();
	}
	Mesh->MaterialList[Material_Index].deMat = deMat;
	int flag=0;

	LPDIRECTXFILEOBJECT pChildObject;
	while (SUCCEEDED(pMaterialData->GetNextObject(&pChildObject)))
	{
		LPDIRECTXFILEDATA pTextureData;
		if (SUCCEEDED(pChildObject->QueryInterface(IID_IDirectXFileData,(VOID **)&pTextureData)))
		{
			const GUID *pGuid;
			pTextureData->GetType(&pGuid);

			if (*pGuid == TID_D3DRMTextureFilename)
			{
				char **string;
				flag=1;
				BOOL Texture_Exists = false;
				pTextureData->GetData(NULL,&dwSize,(VOID **)&string);

				DWORD a;
				for (a = 0; a < deXNumTextures; a++)
				{
					if( !lstrcmpi( &deXTextureList[a].Texture_Name[0], *string ) )
					{
						Texture_Exists=true;
						Mesh->MaterialList[Material_Index].TextureIndex = a;
					}
				}

				if (Texture_Exists==false)
				{
					deXNumTextures++;
					if (deXNumTextures >= NUMTEXTURES)
					{
						DEBUGMSG1("Too many textures: %d", deXNumTextures);
						deXNumTextures = NUMTEXTURES;
					}
					deXTextureList[deXNumTextures-1].RenderTexture = NULL;
					lstrcpyn(&deXTextureList[deXNumTextures-1].Texture_Name[0], *string, 252);
					Mesh->MaterialList[Material_Index].TextureIndex = deXNumTextures-1;
				}
			}
			ReleaseCOM(pTextureData);
		}
		ReleaseCOM(pChildObject);
	}

	if (flag==0)
	{
		Mesh->MaterialList[Material_Index].TextureIndex=0;
	}
}

void GetFrame(LPDIRECTXFILEDATA pFrameData, deXMesh *Parent)
{
	deXMesh *FrameObject = new deXMesh();// create a new frame
	LPDIRECTXFILEOBJECT pChildObject;
	while (SUCCEEDED(pFrameData->GetNextObject(&pChildObject)))
	{
		LPDIRECTXFILEDATA pChildData;
		if (SUCCEEDED(pChildObject->QueryInterface(IID_IDirectXFileData,(VOID **) &pChildData)))
		{
			const GUID * pGuid;
			pChildData->GetType(&pGuid);

			if (*pGuid == TID_D3DRMFrameTransformMatrix)
			{
				DWORD dwSize;
				VOID * pData;
				pChildData->GetData(NULL,&dwSize,(VOID **)&pData);
				FrameObject->Matrix = *((D3DMATRIX *)pData);
			}
			else if (*pGuid==TID_D3DRMFrame)
			{
				GetFrame(pChildData, FrameObject);
			}
			else if (*pGuid==TID_D3DRMMesh)
			{

				GetMesh(pChildData, FrameObject);
			}

			ReleaseCOM(pChildData);
		}
		ReleaseCOM(pChildObject);
	}

	Parent->AddChild(FrameObject);
}



// deStaticBrush friend
deBoolean IdeBrush_LoadFromXFile(const char * filename, deTList<IdeStaticBrush*> & brushplist)
{
	deBoolean retval = deFALSE;
	if (!filename)
		return deFALSE;

	deXMesh * mesh = deXLoader_LoadX(filename);
	if (!mesh)
		return deFALSE;

	retval = MakeStaticBrushList(mesh, brushplist);
	delete mesh;

	return retval;
}

// deStaticBrush friend
deBoolean MakeStaticBrushList(deXMesh * mesh, deTList<IdeStaticBrush*> & brushplist)
{
	if (mesh->HasVerts)
	{
		D3DXVECTOR3 tempd3dvec;
		deStaticBrush * brush = NULL;
		BIndexList bil;
		unsigned int i;

		bil.numpoints = mesh->NumVerts;
		bil.numtexstages = 1;
		bil.numindices = mesh->NumIndices;

		bil.indices = mesh->Indices;

		bil.positions = new deVertex[bil.numpoints];
		bil.normals = new deVertex[bil.numpoints];
		bil.uvcoords = new deTexCoord[bil.numpoints];

		for (i = 0; i < bil.numpoints; i++)
		{
			if (mesh->VertList)
			{
				D3DXVec3TransformCoord((D3DXVECTOR3*)(&(mesh->VertList[i])), (D3DXVECTOR3*)(&(mesh->VertList[i])), (D3DXMATRIX*)(&(mesh->Matrix)));
				
				bil.positions[i].x = mesh->VertList[i].x;
				bil.positions[i].y = mesh->VertList[i].y;
				bil.positions[i].z = mesh->VertList[i].z;
			}

			if (mesh->HasNorms && mesh->NormList)
			{
				D3DXVec3TransformNormal((D3DXVECTOR3*)(&(mesh->NormList[i])), (D3DXVECTOR3*)(&(mesh->NormList[i])), (D3DXMATRIX*)(&(mesh->Matrix)));
				bil.normals[i].x = mesh->NormList[i].x;
				bil.normals[i].y = mesh->NormList[i].y;
				bil.normals[i].z = mesh->NormList[i].z;
			}
			if (mesh->HasCoords && mesh->CoordList)
			{
				bil.uvcoords[i].u = mesh->CoordList[i].u;
				bil.uvcoords[i].v = mesh->CoordList[i].v;
			}
		}

		IdeBitmapProxy * BMP = NULL;
		IdeRenderTexture * TextureState = NULL;
		if(NULL == deXTextureList[mesh->MaterialList[0].TextureIndex].RenderTexture)
		{
			//BMP = new deBitmap(deXTextureList[mesh->MaterialList[0].TextureIndex].Texture_Name, DEBITMAP_TYPE_BMP);
			IdeResourceBase * resource = IdeResourceManager_GetManager()->GetResource(deXTextureList[mesh->MaterialList[0].TextureIndex].Texture_Name, NULL);
			BMP = IdeBitmap_CreateProxy(resource);
			if (BMP)
			{
				TextureState = IdeRenderState_CreateRenderTexture();
				if (!TextureState)
					DEBUGRETURN(deFALSE, "MakeStaticBrushList: error creating TextureState");
				TextureState->Lock();
				TextureState->SetBitmap(0,BMP);
				BMP->Release();
				TextureState->SetColorArg(0,1,IdeRenderTexture::TEXTUREARG_TEXTURE);
				TextureState->SetColorArg(0,2,IdeRenderTexture::TEXTUREARG_DIFFUSE);
				if (resource)
					TextureState->SetColorOperation(0, IdeRenderTexture::TEXTUREOP_MODULATE);
				else
					TextureState->SetColorOperation(0, IdeRenderTexture::TEXTUREOP_SELECTARG2);
				TextureState->SetAlphaOperation(0, IdeRenderTexture::TEXTUREOP_DISABLE);
				TextureState->Unlock();
				deXTextureList[mesh->MaterialList[0].TextureIndex].RenderTexture = TextureState;
			}
		}
		else
		{
			TextureState = deXTextureList[mesh->MaterialList[0].TextureIndex].RenderTexture;
			TextureState->Claim();
		}
		brush = new deStaticBrush;
		brush->SetTextureState(TextureState);
		brush->AddIndexedBuffer(bil);
		brush->m_DiffuseColor = 0xffffffff;
		brush->BuildIndexedBuffers();
		if (TextureState)
			TextureState->Release();

//		deMatrix4 M;
//		M.FromD3DMatrix(&(mesh->Matrix));
//		brush->SetWorldTransform(M);

		delete[] bil.positions;
		delete[] bil.normals;
		delete[] bil.uvcoords;

		brushplist.AddElement(brush);
	}

	if (mesh->Next)
	{
		D3DXMATRIX oldmat,newmat,currmat;
		currmat = mesh->Matrix;
		oldmat = mesh->Next->Matrix;
		newmat = oldmat * currmat;
		mesh->Next->Matrix = newmat;
		MakeStaticBrushList(mesh->Next, brushplist);
	}
	if (mesh->Child)
	{
		D3DXMATRIX oldmat,newmat,currmat;
		currmat = mesh->Matrix;
		oldmat = mesh->Child->Matrix;
		newmat = oldmat * currmat;
		mesh->Child->Matrix = newmat;
		MakeStaticBrushList(mesh->Child, brushplist);
	}

	return deTRUE;
}

void CountXMeshVerts(deXMesh * mesh, int * Vertices, int * Indices, int * Meshes)
{
	if (mesh->HasVerts)
	{
		int index = mesh->MaterialList[0].TextureIndex;
		Vertices[index] += mesh->NumVerts;
		Indices[index] += mesh->NumIndices;
		Meshes[index] += 1;
	}
	if (mesh->Next)
	{
		CountXMeshVerts(mesh->Next, Vertices, Indices, Meshes);
	}
	if (mesh->Child)
	{
		CountXMeshVerts(mesh->Child, Vertices, Indices, Meshes);
	}
}

deBoolean MakeLargeStaticBrushList(deXMesh * mesh, IdeLargeStaticBrush* pBrush, deTransform& scaletform, int * VertsUsed, int * IndicesUsed)
{
	if (mesh->HasVerts)
	{
		// get a normal-transforming one (can't do scaling, just rotation)
		deTransform normaltform(scaletform);
		normaltform.OrthoNormalize();

		int texindex = mesh->MaterialList[0].TextureIndex;
		int VertOffset = VertsUsed[texindex];
		int IndexOffset = IndicesUsed[texindex];

		IdeVertexBuffer* VBuffer = pBrush->GetVertexBuffer(texindex);
		deBoundsCheckedArray<deVertex> Positions, Normals;
		deBoundsCheckedArray<deTexCoord> Textures0;
//		deBoundsCheckedArray<deARGB> Diffuses;
		deBoundsCheckedArray<DWORD> Indices;
		VBuffer->Lock();
		Positions = (deVertex*)VBuffer->GetBuffer(IdeVertexBuffer::BUFFER_POSITION) + VertOffset;
		Normals = (deVertex*)VBuffer->GetBuffer(IdeVertexBuffer::BUFFER_NORMAL) + VertOffset;
		Textures0 = (deTexCoord*)VBuffer->GetBuffer(IdeVertexBuffer::BUFFER_TEXTURECOORDS0) + VertOffset;
//		deARGB* Diffuses = (deVertex*)VBuffer->GetBuffer(IdeVertexBuffer::BUFFER_DIFFUSE);
		Indices = (DWORD*)VBuffer->GetBuffer(IdeVertexBuffer::BUFFER_INDICES32) + IndexOffset;

		Positions.SetLength(VBuffer->GetVertexCount() - VertOffset);
		Normals.SetLength(Positions.GetLength());
		Textures0.SetLength(Positions.GetLength());
//		Diffuses.SetLength(Positions.GetLength());
		Indices.SetLength(VBuffer->GetIndexCount() - IndexOffset);

		D3DXVECTOR3 tempd3dvec;
		deVertex tempvert;
		unsigned int i;

		for (i = 0; i < mesh->NumVerts; i++)
		{
			if (mesh->VertList)
			{
				D3DXVec3TransformCoord(&tempd3dvec, (D3DXVECTOR3*)(&(mesh->VertList[i])), (D3DXMATRIX*)(&(mesh->Matrix)));
				tempvert = *((deVertex*)(&tempd3dvec));
				scaletform.Transform(tempvert, Positions[i]);
			}

			if (mesh->HasNorms && mesh->NormList)
			{
				D3DXVec3TransformNormal(&tempd3dvec, (D3DXVECTOR3*)(&(mesh->NormList[i])), (D3DXMATRIX*)(&(mesh->Matrix)));
				tempvert = *((deVertex*)(&tempd3dvec));
				normaltform.Transform(tempvert, Normals[i]);
			}

			if (mesh->HasCoords && mesh->CoordList)
			{
				Textures0[i].u = mesh->CoordList[i].u;
				Textures0[i].v = mesh->CoordList[i].v;
			}
		}
		for (i = 0; i < mesh->NumIndices; i++)
		{
#pragma note(this may cause a little problem on large meshes)
			Indices[i] = (DWORD)(mesh->Indices[i] + VertOffset);
		}
		VBuffer->Unlock();

		IdeBitmapProxy * BMP = NULL;
		IdeRenderTexture * TextureState = NULL;
		if(NULL == deXTextureList[mesh->MaterialList[0].TextureIndex].RenderTexture)
		{
			//BMP = new deBitmap(deXTextureList[mesh->MaterialList[0].TextureIndex].Texture_Name, DEBITMAP_TYPE_BMP);
			IdeResourceBase * resource = IdeResourceManager_GetManager()->GetResource(deXTextureList[texindex].Texture_Name, NULL);
			BMP = IdeBitmap_CreateProxy(resource);
			if (BMP)
			{
				TextureState = IdeRenderState_CreateRenderTexture();
				if (!TextureState)
					DEBUGRETURN(deFALSE, "MakeLargeStaticBrushList: error creating TextureState");
				TextureState->Lock();
				TextureState->SetBitmap(0,BMP);
				BMP->Release();
				TextureState->SetColorArg(0,1,IdeRenderTexture::TEXTUREARG_TEXTURE);
				TextureState->SetColorArg(0,2,IdeRenderTexture::TEXTUREARG_DIFFUSE);
				if (resource)
					TextureState->SetColorOperation(0, IdeRenderTexture::TEXTUREOP_MODULATE);
				else
					TextureState->SetColorOperation(0, IdeRenderTexture::TEXTUREOP_SELECTARG2);
				TextureState->SetAlphaOperation(0, IdeRenderTexture::TEXTUREOP_DISABLE);
				TextureState->Unlock();
				deXTextureList[texindex].RenderTexture = TextureState;
			}
		}
		else
		{
			TextureState = deXTextureList[texindex].RenderTexture;
			TextureState->Claim();
		}
		pBrush->SetTexture(texindex, TextureState);
		if (TextureState)
			TextureState->Release();

		VertsUsed[texindex] += mesh->NumVerts;
		IndicesUsed[texindex] += mesh->NumIndices;
	}

	if (mesh->Next)
	{
		D3DXMATRIX oldmat,newmat,currmat;
		currmat = mesh->Matrix;
		oldmat = mesh->Next->Matrix;
		newmat = oldmat * currmat;
		mesh->Next->Matrix = newmat;
		MakeLargeStaticBrushList(mesh->Next, pBrush, scaletform, VertsUsed, IndicesUsed);
	}
	if (mesh->Child)
	{
		D3DXMATRIX oldmat,newmat,currmat;
		currmat = mesh->Matrix;
		oldmat = mesh->Child->Matrix;
		newmat = oldmat * currmat;
		mesh->Child->Matrix = newmat;
		MakeLargeStaticBrushList(mesh->Child, pBrush, scaletform, VertsUsed, IndicesUsed);
	}

	return deTRUE;
}

deBoolean IdeBrush_LoadLargeStaticeFromXFile(const char * filename, IdeLargeStaticBrush* pBrush, const deTransformInfo * XForm)
{
#pragma todo (test me)
	if (!filename)
		DEBUGRETURN(deFALSE, "IdeBrush_LoadLargeStaticeFromXFile: Parameter 'filename' was NULL");
	if (!pBrush)
		DEBUGRETURN(deFALSE, "IdeBrush_LoadLargeStaticeFromXFile: Parameter 'pBrush' was NULL");
	
	// load the file itself
	deXMesh * mesh = deXLoader_LoadX(filename);
	if (!mesh)
		return deFALSE;
	
	deBoolean retval = deFALSE;
	deTransform scaletform;
	{
		// if we have a transform to use, then plug it in. If not, scaletform stays as identity
		if (XForm)
			scaletform = *XForm;
	}

	{
		DWORD i;
		int *VertNum, *IndexNum, *MeshNum;

		if (deXNumTextures <= 0)
			deXNumTextures = 1;
		VertNum = new int[deXNumTextures];
		IndexNum = new int[deXNumTextures];
		MeshNum = new int[deXNumTextures];
		for (i = 0; i < deXNumTextures; ++i)
		{
			VertNum[i] = 0;
			IndexNum[i] = 0;
			MeshNum[i] = 0;
		}
		CountXMeshVerts(mesh, VertNum, IndexNum, MeshNum);
		if (VertNum)
		{
			pBrush->SetNumTextures(deXNumTextures);
			IdeVertexBuffer* ParentBuffer = IdeVertexBuffer_CreateVBuffer();
			if (!ParentBuffer)
			{
				delete mesh;
				return deFALSE;
			}
			ParentBuffer->Lock();
			ParentBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_POSITION, deFALSE);
			ParentBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_NORMAL, deFALSE);
			ParentBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_TEXTURECOORDS0, deFALSE);
//			ParentBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_DIFFUSE, deFALSE);
			ParentBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_INDICES32, deFALSE);
			ParentBuffer->Unlock();
			IdeVertexBuffer* ChildBuffer;
			for (i = 0; i < deXNumTextures; ++i)
			{
				ChildBuffer = IdeVertexBuffer_CreateSubVBuffer(ParentBuffer);
				ChildBuffer->Lock();
				ChildBuffer->SetBufferSize(VertNum[i], deFALSE);
				ChildBuffer->SetBufferSize(IndexNum[i], deTRUE);
				ChildBuffer->SetRenderType(IdeVertexBuffer::RENDER_TRIANGLELIST);
				ChildBuffer->Unlock();
				pBrush->SetVertexBuffer(i, ChildBuffer);
				ChildBuffer->Release();
			}
			ParentBuffer->Release();
		}
		else
		{
			DEBUGMSG1("X File contained no vertices: '%s'", filename);
			return deTRUE;
		}

		for (i = 0; i < deXNumTextures; ++i)
		{
			VertNum[i] = 0;
			IndexNum[i] = 0;
		}

		retval = MakeLargeStaticBrushList(mesh, pBrush, scaletform, VertNum, IndexNum);
		delete mesh;
		delete[] VertNum;
		delete[] IndexNum;
		delete[] MeshNum;
	}
	
	return retval;
}

struct xmeshdata_t
{
	deMeshVertexData* vdata;
	deMeshIndexData* idata;
	int* VertsUsed;
	int* IndicesUsed;
};

deBoolean MakeMeshList(const deString2& path, deXMesh * xmesh, deTransform& scaletform, xmeshdata_t * meshdata)
{
	if (xmesh->HasVerts)
	{
		// get a normal-transforming one (can't do scaling, just rotation)
		deTransform normaltform(scaletform);
		normaltform.OrthoNormalize();

		int texindex = xmesh->MaterialList[0].TextureIndex;
		int VertOffset = meshdata->VertsUsed[texindex];
		int IndexOffset = meshdata->IndicesUsed[texindex];

		deBoundsCheckedArray<deVertex> Positions, Normals;
		deBoundsCheckedArray<deTexCoord> Textures0;
//		deBoundsCheckedArray<deARGB> Diffuses;
		deBoundsCheckedArray<u16> Indices;
		Positions = meshdata->vdata[texindex].positions + VertOffset;
		Normals = meshdata->vdata[texindex].normals + VertOffset;
		Textures0 = meshdata->vdata[texindex].uvcoords + VertOffset;
//		Diffuses = meshdata->vdata[texindex].colors + VertOffset;
		Indices = meshdata->idata[texindex].indices16 + IndexOffset;

		Positions.SetLength(meshdata->vdata[texindex].numpoints - VertOffset);
		Normals.SetLength(Positions.GetLength());
		Textures0.SetLength(Positions.GetLength());
//		Diffuses.SetLength(Positions.GetLength());
		Indices.SetLength(meshdata->idata[texindex].numindices - IndexOffset);

		D3DXVECTOR3 tempd3dvec;
		deVertex tempvert;
		unsigned int i;

		for (i = 0; i < xmesh->NumVerts; i++)
		{
			if (xmesh->VertList)
			{
				D3DXVec3TransformCoord(&tempd3dvec, (D3DXVECTOR3*)(&(xmesh->VertList[i])), (D3DXMATRIX*)(&(xmesh->Matrix)));
				tempvert = *((deVertex*)(&tempd3dvec));
				scaletform.Transform(tempvert, Positions[i]);
			}

			if (xmesh->HasNorms && xmesh->NormList)
			{
				D3DXVec3TransformNormal(&tempd3dvec, (D3DXVECTOR3*)(&(xmesh->NormList[i])), (D3DXMATRIX*)(&(xmesh->Matrix)));
				tempvert = *((deVertex*)(&tempd3dvec));
				normaltform.Transform(tempvert, Normals[i]);
			}

			if (xmesh->HasCoords && xmesh->CoordList)
			{
				Textures0[i].u = xmesh->CoordList[i].u;
				Textures0[i].v = xmesh->CoordList[i].v;
			}
		}
		for (i = 0; i < xmesh->NumIndices; i++)
		{
#pragma note(this may cause a little problem on large meshes)
			Indices[i] = xmesh->Indices[i] + VertOffset;
		}

		IdeBitmapProxy * BMP = NULL;
		IdeRenderTexture * TextureState = NULL;
		if(NULL == deXTextureList[texindex].RenderTexture)
		{
			//BMP = new deBitmap(deXTextureList[xmesh->MaterialList[0].TextureIndex].Texture_Name, DEBITMAP_TYPE_BMP);
			deString2 texfilename = path;
			texfilename += deXTextureList[texindex].Texture_Name;
			IdeResourceBase * resource = IdeResourceManager_GetManager()->GetResource(texfilename.const_str(), NULL);
			BMP = IdeBitmap_CreateProxy(resource);
			TextureState = IdeRenderState_CreateRenderTexture();
			if (!TextureState)
				DEBUGRETURN(deFALSE, "MakeMeshList: error creating TextureState");
			TextureState->Lock();
			TextureState->SetBitmap(0,BMP);
			TextureState->SetColorArg(0,1,IdeRenderTexture::TEXTUREARG_TEXTURE);
			TextureState->SetColorArg(0,2,IdeRenderTexture::TEXTUREARG_DIFFUSE);
			if (resource)
			{
				TextureState->SetColorOperation(0, IdeRenderTexture::TEXTUREOP_MODULATE);
				resource->Release();
				resource = NULL;
			}
			else
				TextureState->SetColorOperation(0, IdeRenderTexture::TEXTUREOP_SELECTARG2);
			BMP->Release();
			TextureState->SetColorArg(0,2,IdeRenderTexture::TEXTUREARG_DIFFUSE);
			TextureState->SetAlphaOperation(0, IdeRenderTexture::TEXTUREOP_DISABLE);
			TextureState->Unlock();
			deXTextureList[texindex].RenderTexture = TextureState;
			meshdata->idata[texindex].surface = IdeSurface_CreateSurface();
			meshdata->idata[texindex].surface->SetRenderTexture(TextureState);
			meshdata->idata[texindex].surface->SetRenderMaterial(xmesh->MaterialList[0].deMat);
		}

		meshdata->VertsUsed[texindex] += xmesh->NumVerts;
		meshdata->IndicesUsed[texindex] += xmesh->NumIndices;
	}

	if (xmesh->Next)
	{
		D3DXMATRIX oldmat,newmat,currmat;
		currmat = xmesh->Matrix;
		oldmat = xmesh->Next->Matrix;
		newmat = oldmat * currmat;
		xmesh->Next->Matrix = newmat;
		MakeMeshList(path, xmesh->Next, scaletform, meshdata);
	}
	if (xmesh->Child)
	{
		D3DXMATRIX oldmat,newmat,currmat;
		currmat = xmesh->Matrix;
		oldmat = xmesh->Child->Matrix;
		newmat = oldmat * currmat;
		xmesh->Child->Matrix = newmat;
		MakeMeshList(path, xmesh->Child, scaletform, meshdata);
	}

	return deTRUE;
}

deBoolean IdeMesh_LoadStaticFromXFile(const char * filename, IdeMesh* pMesh, const deTransformInfo * Transform)
{
#pragma todo(implement IdeMesh_LoadStaticFromXFile)
//	return deFALSE;

	if (!filename)
		DEBUGRETURN(deFALSE, "IdeBrush_LoadLargeStaticeFromXFile: Parameter 'filename' was NULL");
	if (!pMesh)
		DEBUGRETURN(deFALSE, "IdeBrush_LoadLargeStaticeFromXFile: Parameter 'pMesh' was NULL");

	// load the file itself
	deXMesh * xmesh = deXLoader_LoadX(filename);
	if (!xmesh)
		return deFALSE;

	deString2 path = filename;
	int x = path.Find('/', 0, deString2::search_backwards);
	path.Trim(x+1);
	
	deBoolean retval = deFALSE;
	deTransform scaletform;
	// if we have a transform to use, then plug it in. If not, scaletform stays as identity
	if (Transform)
		scaletform = *Transform;

	DWORD i;
	xmeshdata_t meshdata;
	int *MeshNum;
	
	if (deXNumTextures <= 0)
		deXNumTextures = 1;
	MeshNum = new int[deXNumTextures];
	meshdata.VertsUsed = new int[deXNumTextures];
	meshdata.IndicesUsed = new int[deXNumTextures];
	meshdata.vdata = new deMeshVertexData[deXNumTextures];
	meshdata.idata = new deMeshIndexData[deXNumTextures];
	memset(meshdata.vdata, 0, deXNumTextures * sizeof(deMeshVertexData));
	memset(meshdata.idata, 0, deXNumTextures * sizeof(deMeshIndexData));
	for (i = 0; i < deXNumTextures; ++i)
	{
		meshdata.VertsUsed[i] = 0;
		meshdata.IndicesUsed[i] = 0;
		MeshNum[i] = 0;
	}
	CountXMeshVerts(xmesh, meshdata.VertsUsed, meshdata.IndicesUsed, MeshNum);
	if (*meshdata.VertsUsed)
	{
		for (i = 0; i < deXNumTextures; ++i)
		{
			meshdata.vdata[i].numpoints = meshdata.VertsUsed[i];
			meshdata.vdata[i].positions = new deVertex[meshdata.vdata[i].numpoints];
			meshdata.vdata[i].normals = new deVertex[meshdata.vdata[i].numpoints];
			meshdata.vdata[i].uvcoords = new deTexCoord2[meshdata.vdata[i].numpoints];
			meshdata.vdata[i].numtexstages = 1;

			meshdata.idata[i].numindices = meshdata.IndicesUsed[i];
			meshdata.idata[i].indices16 = new u16[meshdata.idata[i].numindices];
		}
	}
	else
	{
		DEBUGMSG1("X File contained no vertices: '%s'", filename);
		return deTRUE;
	}
	
	for (i = 0; i < deXNumTextures; ++i)
	{
		meshdata.VertsUsed[i] = 0;
		meshdata.IndicesUsed[i] = 0;
	}
	
	retval = MakeMeshList(path, xmesh, scaletform, &meshdata);

	for (i = 0; i < deXNumTextures; ++i)
	{
		pMesh->AddVertices(meshdata.vdata[i], meshdata.idata[i].indexoffset);
		pMesh->AddIndices(meshdata.idata[i]);
	}
	pMesh->BuildFromVertices();

	for (i = 0; i < deXNumTextures; ++i)
	{
		if (meshdata.idata[i].surface)
			meshdata.idata[i].surface->Release();
		delete[] meshdata.vdata[i].positions;
		delete[] meshdata.vdata[i].normals;
		delete[] meshdata.vdata[i].uvcoords;
		delete[] meshdata.idata[i].indices16;
	}
	delete xmesh;
	delete[] meshdata.vdata;
	delete[] meshdata.idata;
	delete[] meshdata.VertsUsed;
	delete[] meshdata.IndicesUsed;
	delete[] MeshNum;

	for (DWORD k = 0; k < deXNumTextures; ++k)
	{
		IdeRenderTexture* TextureState = deXTextureList[k].RenderTexture;
		if (TextureState)
			TextureState->Release();
	}
	deXNumTextures = 0;

	return deTRUE;
}

#endif //XLOADER_DEPRECATED

