#include <windows.h>
#include <math.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <fstream.h>
#include "model.h"
#include "vector.h"

Model::Model (int mesh, int numVtx, int numTris)
{
	meshtype = mesh;
	rX = rY = rZ = 0;
	pX = pY = pZ = 0;
	sX = sY = sZ = 1;

	if (numVtx == 0)
		vertex = NULL;
	else
	{
		nVertices = numVtx;
		vertex = new Vertex[numVtx];
	}

	if (numTris == 0)
	{
		triangle = NULL;
		quad = NULL;
	}
	else
	{
		nPrimitives = numTris;
		if (meshtype == MESH_TRI)
			triangle = new Triangle[numTris];
		else
			quad = new Quad[numTris];
	}
	state = 0;

	loadedNormals = false;
	textured = false;
	visible = true;
}

Model::~Model ()
{
	if (vertex) delete vertex;
	if (triangle) delete triangle;
	if (quad) delete quad;
}

void Model::loadCAS (char *filename)
{
	int			i;
	ifstream	file (filename, ios::in|ios::binary|ios::nocreate);

	file.read ((char *)&nVertices, 4);
	file.read ((char *)&nPrimitives, 4);

	resize (nVertices, nPrimitives);

	for (i = 0; i < nVertices; i++)
	{
		file.read ((char *)&(vertex[i].x), 4);
		file.read ((char *)&(vertex[i].y), 4);
		file.read ((char *)&(vertex[i].z), 4);
		vertex[i].r = .5;
		vertex[i].g = .5;
		vertex[i].b = .5;
	}

	for (i = 0; i < nPrimitives; i++)
	{
		int a, b, c;
		file.read ((char *)&(a), 4);
		file.read ((char *)&(b), 4);
		file.read ((char *)&(c), 4);
		triangle[i].v[0] = &vertex[a];
		triangle[i].v[1] = &vertex[b];
		triangle[i].v[2] = &vertex[c];
	}

	for (i = 0; i < nPrimitives; i++)
	{
		GLfloat v[3];
		file.read ((char *)&(v[0]), 4);
		file.read ((char *)&(v[1]), 4);
		file.read ((char *)&(v[2]), 4);
		triangle[i].n = v;
	}
	loadedNormals = true;
	calcNormals ();
}


void Model::resize (int numVtx, int numTris)
{
	if (vertex)
		delete vertex;
	if (triangle)
		delete triangle;
	if (quad)
		delete quad;

	if (numVtx == 0)
		vertex = NULL;
	else
	{
		nVertices = numVtx;
		if (!(vertex = new Vertex[numVtx]))
			MessageBox (NULL, "failed", "vtx", MB_OK);;
	}

	if (numTris == 0)
	{
		if (meshtype == MESH_TRI)
			triangle = NULL;
		else
			quad = NULL;
	}
	else
	{
		nPrimitives = numTris;
		if (meshtype == MESH_TRI)
			triangle = new Triangle[numTris];
		else
			quad = new Quad[numTris];
	}
}

void Model::render ()
{
	// TODO : Add support for attribute settings for each model
	// do this with a display list

	glPushMatrix ();

	glTranslatef (pX, pY, pZ);
	glRotatef (rX,  1,  0,  0);
	glRotatef (rY , 0,  1,  0);
	glRotatef (rZ , 0,  0,  1);
	glScalef (sX, sY, sZ);
	if (textured)
		glBindTexture (GL_TEXTURE_2D, texture);
	if (meshtype == MESH_TRI)
		glBegin (GL_TRIANGLES);
	else
		glBegin (GL_QUADS);

	for (int i = 0; i < nPrimitives; i++)
	{ 
		if (meshtype == MESH_TRI)
		{ 
			if (textured)
				glTexCoord2f (triangle[i].uv[0].u, triangle[i].uv[0].v);
			glColor4f (triangle[i].v[0]->r, triangle[i].v[0]->g, triangle[i].v[0]->b, triangle[i].v[0]->a);
			glNormal3f (triangle[i].v[0]->n[0], triangle[i].v[0]->n[1], triangle[i].v[0]->n[2] );
			glVertex3f (triangle[i].v[0]->x, triangle[i].v[0]->y, triangle[i].v[0]->z);
			
			if (textured)
				glTexCoord2f (triangle[i].uv[1].u, triangle[i].uv[1].v);
			glColor4f (triangle[i].v[1]->r, triangle[i].v[1]->g, triangle[i].v[1]->b, triangle[i].v[1]->a);
			glNormal3f (triangle[i].v[1]->n.x(), triangle[i].v[1]->n.y(), triangle[i].v[1]->n.z());
			glVertex3f (triangle[i].v[1]->x, triangle[i].v[1]->y, triangle[i].v[1]->z);
			
			if (textured)
				glTexCoord2f (triangle[i].uv[2].u, triangle[i].uv[2].v);
			glColor4f (triangle[i].v[2]->r, triangle[i].v[2]->g, triangle[i].v[2]->b, triangle[i].v[2]->a);
			glNormal3f (triangle[i].v[2]->n.x(), triangle[i].v[2]->n.y(), triangle[i].v[2]->n.z());
			glVertex3f (triangle[i].v[2]->x, triangle[i].v[2]->y, triangle[i].v[2]->z);
		}
		else
		{
			if (textured)
				glTexCoord2f (quad[i].uv[0].u, quad[i].uv[0].v);
			glColor4f (quad[i].v[0]->r, quad[i].v[0]->g, quad[i].v[0]->b, quad[i].v[0]->a);
			glNormal3f (quad[i].v[0]->n[0], quad[i].v[0]->n[1], quad[i].v[0]->n[2] );
			glVertex3f (quad[i].v[0]->x, quad[i].v[0]->y, quad[i].v[0]->z);
			
			if (textured)
				glTexCoord2f (quad[i].uv[1].u, quad[i].uv[1].v);
			glColor4f (quad[i].v[1]->r, quad[i].v[1]->g, quad[i].v[1]->b, quad[i].v[1]->a);
			glNormal3f (quad[i].v[1]->n.x(), quad[i].v[1]->n.y(), quad[i].v[1]->n.z());
			glVertex3f (quad[i].v[1]->x, quad[i].v[1]->y, quad[i].v[1]->z);
			
			if (textured)
				glTexCoord2f (quad[i].uv[2].u, quad[i].uv[2].v);
			glColor4f (quad[i].v[2]->r, quad[i].v[2]->g, quad[i].v[2]->b, quad[i].v[2]->a);
			glNormal3f (quad[i].v[2]->n.x(), quad[i].v[2]->n.y(), quad[i].v[2]->n.z());
			glVertex3f (quad[i].v[2]->x, quad[i].v[2]->y, quad[i].v[2]->z);

			if (textured)
				glTexCoord2f (quad[i].uv[3].u, quad[i].uv[3].v);
			glColor4f (quad[i].v[3]->r, quad[i].v[3]->g, quad[i].v[3]->b, quad[i].v[3]->a);
			glNormal3f (quad[i].v[3]->n.x(), quad[i].v[3]->n.y(), quad[i].v[3]->n.z());
			glVertex3f (quad[i].v[3]->x, quad[i].v[3]->y, quad[i].v[3]->z);
		} 
	}
	glEnd ();

	glPopMatrix ();
}


void Model::calcNormals ()
{
	// BAAAAD Voodoo!
	// generates VeRy UgLy vertex normals!
	// this is a major FIXME!

	int		i;

	if (!loadedNormals)		// calculate face normals if necessary
	{
		for (i = 0; i < nPrimitives; i++)
		{
			if (meshtype == MESH_TRI)
			{
				CVector a  (triangle[i].v[1]->x - triangle[i].v[0]->x, triangle[i].v[1]->y - triangle[i].v[0]->y, triangle[i].v[1]->z - triangle[i].v[0]->z);
				CVector b  (triangle[i].v[2]->x - triangle[i].v[0]->x, triangle[i].v[2]->y - triangle[i].v[0]->y, triangle[i].v[2]->z - triangle[i].v[0]->z);

				triangle[i].n.cross (a, b);
				triangle[i].n.normalize ();
			}
			else
			{
				CVector a  (quad[i].v[1]->x - quad[i].v[0]->x, quad[i].v[1]->y - quad[i].v[0]->y, quad[i].v[1]->z - quad[i].v[0]->z);
				CVector b  (quad[i].v[2]->x - quad[i].v[0]->x, quad[i].v[2]->y - quad[i].v[0]->y, quad[i].v[2]->z - quad[i].v[0]->z);

				quad[i].n.cross (a, b);
				quad[i].n.normalize ();
			}

		}
	}

	for (i = 0; i < nVertices; i++)
	{
		vertex[i].n.x(0);
		vertex[i].n.y(0);
		vertex[i].n.z(0);
	}

	for (i = 0; i < nPrimitives; i++)
	{
		if (meshtype == MESH_TRI)
		{
			triangle[i].v[0]->n += triangle[i].n;
			triangle[i].v[1]->n += triangle[i].n;
			triangle[i].v[2]->n += triangle[i].n;
		}
		else
		{
			quad[i].v[0]->n += quad[i].n;
			quad[i].v[1]->n += quad[i].n;
			quad[i].v[2]->n += quad[i].n;
		}
	}

	for (i = 0; i < nVertices; i++)
	{
		vertex[i].n.normalize ();
	}
}
/*
void Model::scale( GLfloat xs, GLfloat ys, GLfloat zs )
{
int i=0;

for ( i=0; i<nVertices; i++ )
	{
	vertex[i].x = vertex[i].x*xs; 
	vertex[i].y = vertex[i].y*ys;  
	vertex[i].z = vertex[i].z*xs; 
	}
} */