#ifndef _3DSLOADER_H
#define _3DSLOADER_H

#pragma warning(disable:4995)

#include <d3dx8.h>
#include <stdio.h>
#include <vector.h>
#include "GFDebugHandler.h"

#ifndef DXUTIL_H
#define SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }
#endif

////OBJECT FORMAT/////////////////////////////////////////////////////////////////////
struct OBJFACE
{
	int vertIndex[3];			// indices for the verts that make up this triangle
	int coordIndex[3];			// indices for the tex coords to texture this face
};

struct OBJMATERIALINFO
{				
	OBJMATERIALINFO() : textureId(-1) 
	{
		memset(strName, NULL, 256);
		memset(strFile, NULL, 256);
	}

	char		strName[255];	// The texture name
	char		strFile[255];	// The texture file name (If this is set it's a texture map)
	D3DXCOLOR	color;	
	int			textureId;		// the texture ID
};

struct OBJECT3DS 
{
	OBJECT3DS() : numOfVerts(0), numOfFaces(0), numTexVertex(0), materialID(-1), bHasTexture(0), 
				  pVerts(NULL), pNormals(NULL), pTexVerts(NULL), pFaces(NULL)
	{
		memset(strName, NULL, 256);
	}

	int  numOfVerts;			// The number of verts in the model
	int  numOfFaces;			// The number of faces in the model
	int  numTexVertex;			// The number of texture coordinates
	int  materialID;			// The texture ID to use, which is the index into our texture array
	bool bHasTexture;			// This is TRUE if there is a texture map for this object
	char strName[255];			// The name of the object
	D3DXVECTOR3  *pVerts;		// The object's vertices
	D3DXVECTOR3  *pNormals;		// The object's normals
	D3DXVECTOR2  *pTexVerts;	// The texture's UV coordinates
	OBJFACE *pFaces;			// The faces information of the object
};

struct MODEL3DS 
{
	MODEL3DS() : numOfObjects(0), numOfMaterials(0){}
	~MODEL3DS()
	{
		vector<OBJECT3DS>::iterator i;
		i = pObject.begin();

		while(i != pObject.end())
		{
			SAFE_DELETE_ARRAY(((*i).pVerts));
			SAFE_DELETE_ARRAY(((*i).pNormals));
			SAFE_DELETE_ARRAY(((*i).pTexVerts));
			SAFE_DELETE_ARRAY(((*i).pFaces));
			
			i++;
		}
	}

	int numOfObjects;					// The number of objects in the model
	int numOfMaterials;					// The number of materials for the model
	vector<OBJMATERIALINFO> pMaterials;	// The list of material information (Textures and colors)
	vector<OBJECT3DS> pObject;			// The object list for our model
};
//////////////////////////////////////////////////////////////////////////////////////

#define PRIMARY				0x4D4D

#define OBJECTINFO			0x3D3D			// This gives the version of the mesh and is found right before the
											// material and object information
#define VERSION				0x0002			// This gives the version of the .3ds file
#define EDITKEYFRAME		0xB000			// This is the header for all of the key frame info

#define MATERIAL			0xAFFF			// This stored the texture info
#define OBJECT				0x4000			// This stores the faces, vertices, etc...

#define MATNAME				0xA000			// This holds the material name
#define MATDIFFUSE			0xA020			// This holds the color of the object/material
#define MATMAP				0xA200			// This is a header for a new material
#define MATMAPFILE			0xA300			// This holds the file name of the texture

#define OBJECT_MESH			0x4100			// This lets us know that we are reading a new object

#define OBJECT_VERTICES     0x4110			// The objects vertices
#define OBJECT_FACES		0x4120			// The objects faces
#define OBJECT_MATERIAL		0x4130			// This is found if the object has a material, either texture map or color
#define OBJECT_UV			0x4140			// The UV texture coordinates

struct tIndices 
{		
	unsigned short a, b, c, bVisible;		// This will hold point 1, 2, and 3 index's into the vertex array plus a visible flag
};

struct tChunk
{
	unsigned short int ID;					// The chunk's ID		
	unsigned int length;					// The length of the chunk
	unsigned int bytesRead;					// The amount of bytes read within that chunk
};

class CLoad3DS
{
public:
	CLoad3DS();							

	bool Import3DS(MODEL3DS *pModel, char *strFileName);

private:

	int  GetString(char *);
	void ReadChunk(tChunk *);
	void ProcessNextChunk(MODEL3DS *pModel, tChunk *);
	void ProcessNextObjectChunk(MODEL3DS *pModel, OBJECT3DS *pObject, tChunk *);
	void ProcessNextMaterialChunk(MODEL3DS *pModel, tChunk *);
	void ReadColorChunk(OBJMATERIALINFO *pMaterial, tChunk *pChunk);
	void ReadVertices(OBJECT3DS *pObject, tChunk *);
	void ReadVertexIndices(OBJECT3DS *pObject, tChunk *);
	void ReadUVCoordinates(OBJECT3DS *pObject, tChunk *);
	void ReadObjectMaterial(MODEL3DS *pModel, OBJECT3DS *pObject, tChunk *pPreviousChunk);
	void ComputeNormals(MODEL3DS *pModel);
	void CleanUp();
	
	FILE *m_FilePointer;
	
	tChunk *m_CurrentChunk;
	tChunk *m_TempChunk;
};

#endif