//============================================================
// Program:		CGFSmartLoader
// Description:	Builds Optimal Sized Vertex Buffers
// Author:		Benjamin Gottemoller
// Website:		http://www.particlefield.com
// Date:		who knows
// Legal:		Licensed under the gnu GPL (see gpl.txt for details)
//============================================================

#include "GameFrameSmartLoader.h"
#include "GFDebugHandler.h"
#include "GameFrame.h"

CGFSmartLoader::CGFSmartLoader()
{
	GFParent = NULL;
	memset(ModelPath, NULL, MAX_PATH);
	memset(TexturePath, NULL, MAX_PATH);
}

CGFSmartLoader::~CGFSmartLoader()
{

}

void CGFSmartLoader::SetSearchPaths(char *model_path, char *texture_path)
{
	int index = 0;
	
	strcpy(ModelPath, model_path);
	index = (int)strlen(ModelPath) - 1;
	if(ModelPath[index - 1] != '\\') strcat(ModelPath, "\\");

	strcpy(TexturePath, texture_path);
	index = (int)strlen(TexturePath) - 1;
	if(TexturePath[index - 1] != '\\') strcat(TexturePath, "\\");

}

int CGFSmartLoader::EnqueueModelFile(char *file)
{
	char *data;
	if(file == NULL) return 0;
	data = new char[MAX_PATH + 256];
	if(data == NULL) return 0;
	memset(data, NULL, MAX_PATH + 256);
	strcpy(data, ModelPath);
	strcat(data, file);

	ModelFiles.push_back(data);

	return 1;
}

int CGFSmartLoader::ProcessModelQueue(GameFrame *gfparent, int desired_vb_size)
{
	GFParent = gfparent;
	int i = 0, j = 0;
	char msg[400];
	int cl_current_vb_size = 0;			//Colored Lit VB Size
	int ctl_current_vb_size = 0;		//Colored Textured Lit VB Size
	char *file_path = NULL;
	MODEL3DS *model = NULL;
	list< MODEL3DS * > cl_model_data;	//Colored Lit Model Data
	list< MODEL3DS * > ctl_model_data;	//Colored Textured Lit Model Data
	list< int >	order;
	list< list< int > > cl_model_indices;
	list< list< int > > ctl_model_indices;
	int model_count = 0;
	DWORD model_type = 0;				//0 is Colored Lit, 1 is Colored Textured Lit

	while(ModelFiles.size() > 0)
	{
		CLoad3DS LoaderObject;
		
		file_path = ModelFiles.front();
		ModelFiles.pop_front();

		model = new MODEL3DS;
		if(model == NULL) return 0;
		//Fix Me-->>>>>>>>>>>>>>>>>>>>>>>>
		Confirm(LoaderObject.Import3DS(model, file_path) != 0);
		
		//Determine The Model Type
		model_type = 0;
		for(i=0; i<model->numOfObjects; i++)
		{
			if((model->pObject[i].bHasTexture) && (model->pObject[i].pTexVerts != NULL))
			{
				model_type = 1;
			}
		}

		model_count++;
		order.push_back(model_type);

		if(model_type == 0)	//Colored Lit Model Type
		{
			for(i=0; i<model->numOfObjects; i++)
			{
				cl_current_vb_size += (model->pObject[i].numOfFaces * 3);	//Using triangle lists
			}
			
			cl_model_data.push_back(model);
		}
		else	//Colored Textured Lit Model Type
		{
			for(i=0; i<model->numOfObjects; i++)
			{
				ctl_current_vb_size += (model->pObject[i].numOfFaces * 3);	//Using triangle lists
			}

			ctl_model_data.push_back(model);
		}

		if((cl_current_vb_size >= desired_vb_size) || ((ModelFiles.size() <= 0) && (cl_current_vb_size > 0)))
		{
			int vertex_library_index = 0;
			int vindex = 0;
			OBJNODE tmp_object;
			COLOREDLITVERTEX *vertices = NULL;
			list<int> ThisObjLibIndices;

			vertex_library_index = GFParent->VertexLib.AddVertexBuffer(cl_current_vb_size, 
																	   sizeof(COLOREDLITVERTEX), 
																	   D3DFVF_COLOREDLITVERTEX);
			Confirm(vertex_library_index != -1);
			if(vertex_library_index != -1)
			{
				sprintf(msg, "(Colored Lit) Vertex Buffer created with %d vertices.", cl_current_vb_size);
				Message(msg);
			}
			
			GFParent->VertexLib.LockBuffer(vertex_library_index, (BYTE **) &vertices);
			
			while(!cl_model_data.empty())
			{
				model = cl_model_data.front();
				cl_model_data.pop_front();

				for(i=0; i<model->numOfObjects; i++)
				{
					tmp_object.StartVertex = vindex;
					tmp_object.PrimitiveCount = model->pObject[i].numOfFaces;  //this works because we're using tri-lists
					tmp_object.PrimitiveType = D3DPT_TRIANGLELIST;
					tmp_object.TextureLibraryIndex = -1;
					tmp_object.MaterialLibraryIndex = -1;
					tmp_object.VertexLibraryIndex = vertex_library_index;
					memcpy(tmp_object.ObjectName, model->pObject[i].strName, 256);

					for(j=0; j<(model->pObject[i].numOfFaces); j++)
					{
						//----fill vb with vertices----//
						vertices[vindex].position.x = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[0]].x;
						vertices[vindex].position.y = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[0]].y;
						vertices[vindex].position.z = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[0]].z;

						vertices[vindex+1].position.x = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[1]].x;
						vertices[vindex+1].position.y = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[1]].y;
						vertices[vindex+1].position.z = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[1]].z;

						vertices[vindex+2].position.x = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[2]].x;
						vertices[vindex+2].position.y = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[2]].y;
						vertices[vindex+2].position.z = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[2]].z;
						
						//----fill vb with colors----//
						if(model->pMaterials.size() > 0)
						{
							vertices[vindex].diffuse   = model->pMaterials[model->pObject[i].materialID].color;
							vertices[vindex+1].diffuse = model->pMaterials[model->pObject[i].materialID].color;
							vertices[vindex+2].diffuse = model->pMaterials[model->pObject[i].materialID].color;
						}
						else
						{
							//If there are no materials, use black & white checkers
							float color;
							color = (float)255*(vindex%2);
							vertices[vindex].diffuse =   D3DXCOLOR(color, color, color, 0);
							vertices[vindex+1].diffuse = D3DXCOLOR(color, color, color, 0);
							vertices[vindex+2].diffuse = D3DXCOLOR(color, color, color, 0);
						}

						vertices[vindex].normal   = model->pObject[i].pNormals[model->pObject[i].pFaces[j].vertIndex[0]];
						vertices[vindex+1].normal = model->pObject[i].pNormals[model->pObject[i].pFaces[j].vertIndex[1]];
						vertices[vindex+2].normal = model->pObject[i].pNormals[model->pObject[i].pFaces[j].vertIndex[2]];

						vindex+=3;
					}

					D3DXComputeBoundingSphere((void *)(vertices + tmp_object.StartVertex), 
						                      (model->pObject[i].numOfFaces * 3), 
											  D3DFVF_COLOREDLITVERTEX, 
											  &(tmp_object.Center),
											  &(tmp_object.Radius));

					D3DXComputeBoundingBox((void *)(vertices + tmp_object.StartVertex), 
						                   (model->pObject[i].numOfFaces * 3), 
										   D3DFVF_COLOREDLITVERTEX, 
										   &(tmp_object.BoxMin),
										   &(tmp_object.BoxMax));

					ThisObjLibIndices.push_back( GFParent->ObjectLib.AddObject(&tmp_object) );
					Confirm( ThisObjLibIndices.back() != -1 );
				}

				cl_model_indices.push_back(ThisObjLibIndices);
				while(!ThisObjLibIndices.empty()) ThisObjLibIndices.pop_front();
				
				SAFE_DELETE(model);
			}

			GFParent->VertexLib.UnlockBuffer(vertex_library_index);
			cl_current_vb_size = 0;
		}

		if((ctl_current_vb_size >= desired_vb_size) || ((ModelFiles.size() <= 0) && (ctl_current_vb_size > 0)))
		{
			int vertex_library_index = 0;
			int vindex = 0;
			OBJNODE tmp_object;
			COLOREDTEXTUREDLITVERTEX *vertices = NULL;
			list<int> ThisObjLibIndices;
			
			vertex_library_index = GFParent->VertexLib.AddVertexBuffer(ctl_current_vb_size, 
																	   sizeof(COLOREDTEXTUREDLITVERTEX), 
																	   D3DFVF_COLOREDTEXTUREDLITVERTEX);
			Confirm(vertex_library_index != -1);
			if(vertex_library_index != -1)
			{
				sprintf(msg, "(Colored Textured Lit) Vertex Buffer created with %d vertices.", ctl_current_vb_size);
				Message(msg);
			}

			GFParent->VertexLib.LockBuffer(vertex_library_index, (BYTE **) &vertices);
		
			while(!ctl_model_data.empty())
			{
				model = ctl_model_data.front();
				ctl_model_data.pop_front();

				for(i=0; i<model->numOfObjects; i++)
				{
					char texture_path[MAX_PATH + 256];
					memset(texture_path, NULL, MAX_PATH + 256);

					tmp_object.StartVertex = vindex;
					tmp_object.PrimitiveCount = model->pObject[i].numOfFaces;  //this works because we're using tri-lists
					tmp_object.PrimitiveType = D3DPT_TRIANGLELIST;	
					
					strcpy(texture_path, TexturePath);
					strcat(texture_path, model->pMaterials[model->pObject[i].materialID].strFile);
					tmp_object.TextureLibraryIndex = GFParent->TextureLib.AddTexture(texture_path);
					if(tmp_object.TextureLibraryIndex == -1)
					{
						sprintf(msg, "Texture Load Failure: (Path: %s),    (Name: %s)", 
								model->pMaterials[model->pObject[i].materialID].strFile,
								model->pMaterials[model->pObject[i].materialID].strName);
						Message(msg);
						tmp_object.TextureLibraryIndex = GFParent->TextureLib.FindTexture("MISSING_TEXTURE.jpg");
						if(tmp_object.TextureLibraryIndex == -1)
						{
							tmp_object.TextureLibraryIndex = GFParent->TextureLib.AddTexture("MISSING_TEXTURE.jpg");
						}
						Confirm(tmp_object.TextureLibraryIndex != -1);
						Confirm(model->pObject[i].pTexVerts != NULL);
					}

					tmp_object.MaterialLibraryIndex = -1;
					tmp_object.VertexLibraryIndex = vertex_library_index;
					memcpy(tmp_object.ObjectName, model->pObject[i].strName, 256);

					for(j=0; j<(model->pObject[i].numOfFaces); j++)
					{
						//----fill vb with vertices----//
						vertices[vindex].position.x = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[0]].x;
						vertices[vindex].position.y = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[0]].y;
						vertices[vindex].position.z = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[0]].z;

						vertices[vindex+1].position.x = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[1]].x;
						vertices[vindex+1].position.y = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[1]].y;
						vertices[vindex+1].position.z = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[1]].z;

						vertices[vindex+2].position.x = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[2]].x;
						vertices[vindex+2].position.y = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[2]].y;
						vertices[vindex+2].position.z = model->pObject[i].pVerts[model->pObject[i].pFaces[j].vertIndex[2]].z;
						
						//----fill vb with colors----//
						if(model->pMaterials.size() > 0)
						{
							vertices[vindex].diffuse = model->pMaterials[model->pObject[i].materialID].color;
							vertices[vindex+1].diffuse = model->pMaterials[model->pObject[i].materialID].color;
							vertices[vindex+2].diffuse = model->pMaterials[model->pObject[i].materialID].color;
						}
						else
						{
							//If there are no materials, use black & white checkers
							float color;
							color = (float)255*(vindex%2);
							vertices[vindex].diffuse =   D3DXCOLOR(color, color, color, 0);
							vertices[vindex+1].diffuse = D3DXCOLOR(color, color, color, 0);
							vertices[vindex+2].diffuse = D3DXCOLOR(color, color, color, 0);
						}

						vertices[vindex].normal   = model->pObject[i].pNormals[model->pObject[i].pFaces[j].vertIndex[0]];
						vertices[vindex+1].normal = model->pObject[i].pNormals[model->pObject[i].pFaces[j].vertIndex[1]];
						vertices[vindex+2].normal = model->pObject[i].pNormals[model->pObject[i].pFaces[j].vertIndex[2]];

						//----fill vb with texture coordinates----//
						//Odly enough the coordIndex array is not used here and the vertIndex array takes it's
						//place for determining the pTexVerts index.
						vertices[vindex].tu = model->pObject[i].pTexVerts[model->pObject[i].pFaces[j].vertIndex[0]].x;
						vertices[vindex].tv = model->pObject[i].pTexVerts[model->pObject[i].pFaces[j].vertIndex[0]].y;

						vertices[vindex+1].tu = model->pObject[i].pTexVerts[model->pObject[i].pFaces[j].vertIndex[1]].x;
						vertices[vindex+1].tv = model->pObject[i].pTexVerts[model->pObject[i].pFaces[j].vertIndex[1]].y;

						vertices[vindex+2].tu = model->pObject[i].pTexVerts[model->pObject[i].pFaces[j].vertIndex[2]].x;
						vertices[vindex+2].tv = model->pObject[i].pTexVerts[model->pObject[i].pFaces[j].vertIndex[2]].y;

						vindex+=3;
					}

					D3DXComputeBoundingSphere((void *)(vertices + tmp_object.StartVertex), 
						                      (model->pObject[i].numOfFaces * 3), 
											  D3DFVF_COLOREDTEXTUREDLITVERTEX, 
											  &(tmp_object.Center),
											  &(tmp_object.Radius));

					D3DXComputeBoundingBox((void *)(vertices + tmp_object.StartVertex), 
						                   (model->pObject[i].numOfFaces * 3), 
										   D3DFVF_COLOREDTEXTUREDLITVERTEX, 
										   &(tmp_object.BoxMin),
										   &(tmp_object.BoxMax));

					ThisObjLibIndices.push_back( GFParent->ObjectLib.AddObject(&tmp_object) );
					Confirm( ThisObjLibIndices.back() != -1 );
				}

				ctl_model_indices.push_back(ThisObjLibIndices);
				while(!ThisObjLibIndices.empty()) ThisObjLibIndices.pop_front();
				
				SAFE_DELETE(model);
			}

			GFParent->VertexLib.UnlockBuffer(vertex_library_index);
			ctl_current_vb_size = 0;
		}

		SAFE_DELETE_ARRAY(file_path);
	}

	//Now sort everything out so the dequeing order is correct
	while(!order.empty())
	{
		if(order.front() == 0)
		{
			Indices.push_back(cl_model_indices.front());
			cl_model_indices.pop_front();
		}
		else
		{
			Indices.push_back(ctl_model_indices.front());
			ctl_model_indices.pop_front();
		}
		
		order.pop_front();
	}

	return 1;
}

int CGFSmartLoader::DequeProcessedIndices(list< int > *indices)
{
	if(Indices.empty()) return 0;
	*indices = Indices.front();
	Indices.pop_front();
	return 1;
}
