// PROGRAM INCLUDES
#include "model.h"

using namespace std;

model::model()
{
	meshes = 0;
	materials = 0;
}

model::~model()
{
	if (meshes != 0)
        delete [] meshes;
	if (materials != 0)
		delete [] materials;
}

int model::load(std::string path)
{
	int tmpCount = 0;
	string buffer = "";

	ifstream file(path.c_str());

	if (!file)
	{
		// Make sure pointers are zeroed
		meshes = 0;
		materials = 0;
		return MODEL_NOT_FOUND;
	}

	while (!file.eof())
	{
		if (buffer == "//" || buffer == "#")
		{
			while (file.get() != '\n'){}
		}

		if (buffer == "Meshes:")
		{
			// Read in mesh count
			file >> meshCount;
			meshes = new mesh[meshCount];

			for (int i = 0; i < meshCount; i++)
			{
					// Read in mesh name, flags, and material index
					file >> meshes[i].name >> meshes[i].flags >> meshes[i].materialIndex;

					// Read in number of vertices and init the point array inside the mesh
					file >> tmpCount;
					if (tmpCount < 0)
						return MODEL_PARSE_ERROR;
					meshes[i].initVertArray(tmpCount);
					
					// Read in the vertices
					for (int v = 0; v < tmpCount; v++)
						// vertex: flags, x, y, z, u, v, bone index
						file >> meshes[i].vertices[v].flag >> meshes[i].vertices[v].x 
							>> meshes[i].vertices[v].y >> meshes[i].vertices[v].z 
							>> meshes[i].vertices[v].u >> meshes[i].vertices[v].v
							>> meshes[i].vertices[v].boneIndex;

					// Read in number of normals and init its array
					file >> tmpCount;
					if (tmpCount < 0)
						return MODEL_PARSE_ERROR;
					meshes[i].initNormArray(tmpCount);

					// Read in the normals
					for (int n = 0; n < tmpCount; n++)
						// normal: x, y, z
						file >> meshes[i].normals[n].x >> meshes[i].normals[n].y 
							>> meshes[i].normals[n].z; 

					// Read in number of triangles and init its array
					file >> tmpCount;
					if (tmpCount < 0)
						return MODEL_PARSE_ERROR;
					meshes[i].initTriArray(tmpCount);

					// Read in the triangles
					for (int t = 0; t < tmpCount; t++)
						// triangle: flags, vertex index1, vertex index2, 
						// vertex index3, normal index1, normal index 2, 
						// normal index 3, smoothing group
						file >> meshes[i].triangles[t].flag 
							>> meshes[i].triangles[t].vertIndex[0] 
							>> meshes[i].triangles[t].vertIndex[1]
							>> meshes[i].triangles[t].vertIndex[2]
							>> meshes[i].triangles[t].normIndex[0]
							>> meshes[i].triangles[t].normIndex[1]
							>> meshes[i].triangles[t].normIndex[2]
							>> meshes[i].triangles[t].smoothingGroup;
			}
		}

		if (buffer == "Materials:")
		{
			file >> materialCount;
			materials = new material[materialCount];

			for (int i = 0; i < materialCount; i++)
			{
				file >> materials[i].name;

				file >> materials[i].ambient[0] >> materials[i].ambient[1] 
				>> materials[i].ambient[2] >> materials[i].ambient[3];
				
				file >> materials[i].diffuse[0] >> materials[i].diffuse[1] 
				>> materials[i].diffuse[2] >> materials[i].diffuse[3];

				file >> materials[i].specular[0] >> materials[i].specular[1] 
				>> materials[i].specular[2] >> materials[i].specular[3];

				file >> materials[i].emissive[0] >> materials[i].emissive[1] 
				>> materials[i].emissive[2] >> materials[i].emissive[3];

				file >> materials[i].shininess;
				file >> materials[i].transparency;

				file >> materials[i].colorPath;
				file >> materials[i].alphaPath;
                
				materials[i].colorMap = loadJPEG(materials[i].colorPath);
				materials[i].alphaMap = loadJPEG(materials[i].alphaPath);
			}			
		}

        file >> buffer;		
	}

	file.close();

	return 0;
}

void model::render(int n)
{
	// Check make sure the model has materials
	if (materials)
		glBindTexture(GL_TEXTURE_2D, materials[0].colorMap);

	
	// Check and make sure the model has meshs
	if (meshes)
	{
		glBegin(GL_TRIANGLES);
		// Draw the total number of triangles in the choosen mesh
		for (int i = 0; i < meshes[n].triCount; i++)
		{
			// Draw each vertex in the triangle
			for (int v = 0; v < 3; v++)
			{
				glNormal3f(meshes[n].normals[meshes[n].triangles[i].normIndex[v]].x
					, meshes[n].normals[meshes[n].triangles[i].normIndex[v]].y
					, meshes[n].normals[meshes[n].triangles[i].normIndex[v]].z);

				glTexCoord2f(meshes[n].vertices[meshes[n].triangles[i].vertIndex[v]].u
					, meshes[n].vertices[meshes[n].triangles[i].vertIndex[v]].v);

				glVertex3f(meshes[n].vertices[meshes[n].triangles[i].vertIndex[v]].x
					, meshes[n].vertices[meshes[n].triangles[i].vertIndex[v]].y
					, meshes[n].vertices[meshes[n].triangles[i].vertIndex[v]].z);
			}
		}
		glEnd();
	}

}

void model::render(int x, int y, int z)
{
	// Check make sure the model has materials
	if (materials)
		glBindTexture(GL_TEXTURE_2D, materials[0].colorMap);

	
	// Check and make sure the model has meshs
	if (meshes)
	{
		for (int n = 0; n < meshCount; n++)
		{
			glBegin(GL_TRIANGLES);
			// Draw the total number of triangles in the choosen mesh
			for (int i = 0; i < meshes[n].triCount; i++)
			{
				// Draw each vertex in the triangle
				for (int v = 0; v < 3; v++)
				{
					glNormal3f(meshes[n].normals[meshes[n].triangles[i].normIndex[v]].x
						, meshes[n].normals[meshes[n].triangles[i].normIndex[v]].y
						, meshes[n].normals[meshes[n].triangles[i].normIndex[v]].z);

					glTexCoord2f(meshes[n].vertices[meshes[n].triangles[i].vertIndex[v]].u
						, meshes[n].vertices[meshes[n].triangles[i].vertIndex[v]].v);

					glVertex3f(meshes[n].vertices[meshes[n].triangles[i].vertIndex[v]].x
						, meshes[n].vertices[meshes[n].triangles[i].vertIndex[v]].y
						, meshes[n].vertices[meshes[n].triangles[i].vertIndex[v]].z);
				}
			}
			glEnd();
		}
	}

}

GLuint model::loadJPEG(std::string path)
{
	SDL_Surface *TextureImage; 
	GLuint texture;
	
	// Check and load texture image
    if (!(TextureImage = IMG_Load(path.c_str())))
	{
		SDL_FreeSurface(TextureImage);
		return 0;
	}

	// Create the GL texture, bind it, and build it using mipmaping
	glGenTextures(1, &texture);
	glBindTexture(GL_TEXTURE_2D, texture);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
	glTexImage2D( GL_TEXTURE_2D, 0, 3, TextureImage->w,TextureImage->h, 0, GL_RGB
		, GL_UNSIGNED_BYTE, TextureImage->pixels );
	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage->w,TextureImage->h, GL_RGB
		, GL_UNSIGNED_BYTE, TextureImage->pixels);

    if (TextureImage)
	    SDL_FreeSurface(TextureImage);

	return texture;
}
