#include "Model.h"

void Model::init(int fileFormat)
{
	//initializes the Model
	mesh = new Mesh(! source); //targetMesh may not be set properly during matchByFrontiers() algo
	mesh->frameID = model;
	
	char fName[150];
	bool inObj = false, inObj2 = false, inPly = false;
	if (fileFormat == 1) //frameID.obj format that sits in the same folder as executable inside folder \input (for portable batch runs)
	{
		inObj = true;
		sprintf(fName, "data\\%d.obj", mesh->frameID);
	}
	else if (fileFormat == 2) //frameID.off format that sits in the same folder as executable inside folder \input (for portable batch runs)
		sprintf(fName, "data\\%d.off", mesh->frameID);
	else if (fileFormat == 3) //frameID.ply format that sits in the same folder as executable inside folder \input (for portable batch runs)
	{
		inPly = true;
		sprintf(fName, "data\\%d.ply", mesh->frameID);
	}
	else
	{
		cout << "not happen in publicly shared mode\n";
		exit(0);
	}

	if (inObj2)
		loadObj2(fName);
	else if (inObj)
		loadObj(fName);
	else if (inPly)
		loadPly(fName);
	else //in off format
		loadOff(fName);

	cout << "Initial mesh has " << (int) mesh->tris.size() << " tris, " << (int) mesh->verts.size() << " verts, "
		 << (int) mesh->edges.size() << " edges\nInitialization done\n\n";
	mesh->updateNormals();

//not doing below anymore for seahorse 'cos using the connector triangles, i can connect them to the mesh (so not ignored at all as they're important ear vertices); for gorilla, connection not necessary, so simply ignoring them is enough
//	if (fileFormat != -1 && theInput == SEAHORSE_HORSE && source) //mark seahorse's disconnected verts to ignore them during the whole algorithm
	if (fileFormat != -1 && theInput == GORILLA_GIRL && source) //mark gorilla's disconnected verts to ignore them during the whole algorithm
	{
		char fName[250];
		sprintf(fName, "..\\..\\..\\code\\input\\nonrigid3d\\gorilla%d.disconnectedSmallPart.dat", mesh->frameID);
		FILE* fPtr = fopen(fName, "r");
		if (fPtr)
		{
			int a;
			while (fscanf(fPtr, "%d\n", &a) != EOF)
				mesh->verts[a]->disconnected = true;
		}
		else
		{
			cout << "verts in disconnected small part not fread\n";
			exit(0);
		}
	}//*/
}

Mesh* Model::getMesh()
{
	return mesh;
}

void Model::loadObj(char* meshFile)
{
	cout << "Mesh initializing (to model in " << meshFile << " file)..\n";

	FILE* fPtr = fopen(meshFile, "r");
	if (fPtr == 0)
		cout << "cannot read " << meshFile << endl;

	char type;	//type of line: vertex line (v) or face line (f)
	float a, b, c;	//for face lines casting these to int will suffice
	bool first = true;
	float minX, minY, minZ, maxX, maxY, maxZ; //bbox to be used in center-of-bbox calculation
	mesh->minEdgeLen = INF;	mesh->maxEdgeLen = -INF; mesh->edgeLenTotal = 0.0f;
	while (fscanf(fPtr, "%c %f %f %f\n", &type, &a, &b, &c) != EOF) //go till the end of file
		if (type == 'v')
		{
			//in original .obj file, tri.areas ~= .1f and, e.g., split of them deceives >= .01f assertion in addTria wrongly
			a *= SCALE_FACTOR;	b *= SCALE_FACTOR;	c *= SCALE_FACTOR;

			//none of verts are removed/duplicated initially 'cos i read .obj
			float* coords = new float[3];
			coords[0] = a;
			coords[1] = b;
			coords[2] = c;
			mesh->addVertexND(coords); //ND: no duplicate check

			//bbox computation
			if ((int) mesh->verts.size() == 1)
			{
				minX = maxX = a;	minY = maxY = b;	minZ = maxZ = c;
			}
			else
			{
				if (a < minX)	minX = a; else if (a > maxX)	maxX = a;
				if (b < minY)	minY = b; else if (b > maxY)	maxY = b;
				if (c < minZ)	minZ = c; else if (c > maxZ)	maxZ = c;
			}
		}
		else //if (type == 'f')
			mesh->addTriangle((int) a - 1, (int) b - 1, (int) c - 1, true); //-1: obj indices start at 1

	float cobX = (minX+maxX) / 2.0f, cobY = (minY+maxY) / 2.0f, cobZ = (minZ+maxZ) / 2.0f;
	cout << "bbox.center: (" << cobX << ", " << cobY << ", " << cobZ << "); "
		 << "bbox.(w,h,d): (" << maxX-minX << ", " << maxY-minY << ", " << maxZ-minZ << ")\n"
		 << "min <= avg <= maxEdgeLen: " << mesh->minEdgeLen << " <= " << mesh->edgeLenTotal/((int) mesh->edges.size()) << " <= " << mesh->maxEdgeLen << "\n";
	mesh->avgEdgeLen = mesh->edgeLenTotal/((int) mesh->edges.size());
	fclose(fPtr);
	cout << "Initialization done\n\n";
}
void Model::loadObj2(char* meshFile) //use this instead of loadObj() just-above for dog-wolf run
{
	cout << "Mesh initializing (to model in " << meshFile << " file)..\n";

	FILE* fPtr = fopen(meshFile, "r");
	if (fPtr == 0)
		cout << "cannot read " << meshFile << endl;

	char type;	//type of line: vertex line (v) or face line (f)
	float a, b, c;	//for face lines casting these to int will suffice
	bool first = true;
	float minX, minY, minZ, maxX, maxY, maxZ; //bbox to be used in center-of-bbox calculation
	mesh->minEdgeLen = INF;	mesh->maxEdgeLen = -INF; mesh->edgeLenTotal = 0.0f;
type = 'v';
	while (fscanf(fPtr, "%f %f %f\n", &a, &b, &c) != EOF) //missing 'v' and 'f' in each line of .obj2 files [dog-wolf case]
		if (type == 'v')
		{
if (a == -9 && b == -9 && c == -9) { type = 'f'; continue; } //my special .obj2 file starts triangles right after -9 -9 -9 line

			//in original .obj file, tri.areas ~= .1f and, e.g., split of them deceives >= .01f assertion in addTria wrongly
			a *= SCALE_FACTOR;	b *= SCALE_FACTOR;	c *= SCALE_FACTOR;

			//none of verts are removed/duplicated initially 'cos i read .obj
			float* coords = new float[3];
			coords[0] = a, coords[1] = b, coords[2] = c;
			mesh->addVertexND(coords); //ND: no duplicate check

			//bbox computation
			if ((int) mesh->verts.size() == 1)
			{
				minX = maxX = a;	minY = maxY = b;	minZ = maxZ = c;
			}
			else
			{
				if (a < minX)	minX = a; else if (a > maxX)	maxX = a;
				if (b < minY)	minY = b; else if (b > maxY)	maxY = b;
				if (c < minZ)	minZ = c; else if (c > maxZ)	maxZ = c;
			}
		}
		else //if (type == 'f')
			mesh->addTriangle((int) a - 1, (int) b - 1, (int) c - 1, true); //-1: obj indices start at 1

	float cobX = (minX+maxX) / 2.0f, cobY = (minY+maxY) / 2.0f, cobZ = (minZ+maxZ) / 2.0f;
	cout << "bbox.center: (" << cobX << ", " << cobY << ", " << cobZ << "); "
		 << "bbox.(w,h,d): (" << maxX-minX << ", " << maxY-minY << ", " << maxZ-minZ << ")\n"
		 << "min <= avg <= maxEdgeLen: " << mesh->minEdgeLen << " <= " << mesh->edgeLenTotal/((int) mesh->edges.size()) << " <= " << mesh->maxEdgeLen << "\n";
	mesh->avgEdgeLen = mesh->edgeLenTotal/((int) mesh->edges.size());
	fclose(fPtr);

	if (theInput == SEAHORSE_HORSE && source) //connect seahorse's disconnected verts to the rest of the body via connector triangles
	{
		char fName[250];
		sprintf(fName, "..\\..\\..\\code\\input\\nonrigid3d\\seahorse connector triangles.dat");
		fPtr = fopen(fName, "r");
		if (fPtr)
		{
			//seahorse id line followed by 2 lines one for 1 connector triangle for the disconnected left ear and other for another connector triangle for the disconnected right ear
			int a, t, u, v;
			while (fscanf(fPtr, "%d\n", &a) != EOF)
				if (a == mesh->frameID)
				{
					fscanf(fPtr, "%d\t%d\t%d\n", &t, &u, &v);
					mesh->addTriangle(t, u, v, true); //left ear
					fscanf(fPtr, "%d\t%d\t%d\n", &t, &u, &v);
					mesh->addTriangle(t, u, v, true); //right ear
				}
				else
				{
					fscanf(fPtr, "%d\t%d\t%d\n", &t, &u, &v); //skip
					fscanf(fPtr, "%d\t%d\t%d\n", &t, &u, &v); //skip
				}
		}
		else
		{
			cout << "connector triangles to connect disconnected parts not found\n";
			exit(0);
		}
	}

	cout << "Initialization done\n\n";
}
void Model::loadOff(char* meshFile)
{
	cout << "Mesh initializing (to model in " << meshFile << " file)..\n";

	FILE* fPtr = fopen(meshFile, "r");
	if (fPtr == 0)
		cout << "cannot read " << meshFile << endl;

	char off[25];
	fscanf(fPtr, "%s\n", &off); //cout << off << " type file\n";

	float a, b, c, d;	//for face lines and the 2nd line (that gives # of verts, faces, and edges) casting these to int will suffice
	fscanf(fPtr, "%f %f %f\n", &a, &b, &c);
	int nVerts = (int) a, v = 0;

	float minX, minY, minZ, maxX, maxY, maxZ; //bbox to be used in center-of-bbox calculation
	mesh->minEdgeLen = INF;
	mesh->maxEdgeLen = -INF;
	mesh->edgeLenTotal = 0.0f;
	while (v++ < nVerts) //go till the end of verts coord section
	{
		fscanf(fPtr, "%f %f %f\n", &a, &b, &c);

		//in original .off file, tri.areas ~= .1f and, e.g., split of them deceives >= .01f assertion in addTria wrongly
		a *= SCALE_FACTOR;	b *= SCALE_FACTOR;	c *= SCALE_FACTOR;

		//none of verts are removed/duplicated initially 'cos i read .off
		float* coords = new float[3];
		coords[0] = a, coords[1] = b, coords[2] = c;
		mesh->addVertexND(coords); //ND: no duplicate check

		//bbox computation
		if ((int) mesh->verts.size() == 1)
		{
			minX = maxX = a;	minY = maxY = b;	minZ = maxZ = c;
		}
		else
		{
			if (a < minX)	minX = a; else if (a > maxX)	maxX = a;
			if (b < minY)	minY = b; else if (b > maxY)	maxY = b;
			if (c < minZ)	minZ = c; else if (c > maxZ)	maxZ = c;
		}
	}

	//verts ready, time to fill triangles
	while (fscanf(fPtr, "%f %f %f %f\n", &d, &a, &b, &c) != EOF) //go till the end of file
		mesh->addTriangle((int) a, (int) b, (int) c, true); //no -1 'cos idxs start from 0 for off files

	float cobX = (minX+maxX) / 2.0f, cobY = (minY+maxY) / 2.0f, cobZ = (minZ+maxZ) / 2.0f;
	cout << "bbox.center: (" << cobX << ", " << cobY << ", " << cobZ << "); "
		 << "bbox.(w,h,d): (" << maxX-minX << ", " << maxY-minY << ", " << maxZ-minZ << ")\n"
		 << "min <= avg <= maxEdgeLen: " << mesh->minEdgeLen << " <= " << mesh->edgeLenTotal/((int) mesh->edges.size()) << " <= " << mesh->maxEdgeLen << "\n";
	mesh->avgEdgeLen = mesh->edgeLenTotal/((int) mesh->edges.size());
	fclose(fPtr);
	cout << "Initialization done\n\n";
}
void Model::loadPly(char* meshFile)
{
	cout << "Mesh initializing (to model in " << meshFile << " file)...\n";

	FILE* fPtr = fopen(meshFile, "r");
	if (fPtr == 0)
	{
		cout << "cannot read " << meshFile << endl;
		exit(0);
	}

	char ply[25], nVertsStr[25];
	fscanf(fPtr, "%s\n", &ply); //skip "ply" at line 1
	fscanf(fPtr, "%s %s %s\n", &ply, &ply, &ply); //skip "format ascii 1.0" at next line
	fscanf(fPtr, "%s %s %s\n", &ply, &ply, &nVertsStr); //skip "element vertex 12500" at next line
	int nVerts = atoi(nVertsStr), v = 0;
	fscanf(fPtr, "%s %s %s\n", &ply, &ply, &ply); //skip "property float x" at next line
	fscanf(fPtr, "%s %s %s\n", &ply, &ply, &ply); //skip "property float y" at next line
	fscanf(fPtr, "%s %s %s\n", &ply, &ply, &ply); //skip "property float z" at next line
	fscanf(fPtr, "%s %s %s\n", &ply, &ply, &ply); //skip "element face 25000" at next line
	fscanf(fPtr, "%s %s %s %s %s\n", &ply, &ply, &ply, &ply, &ply); //skip "property list uchar int vertex_indices" at next line
	fscanf(fPtr, "%s\n", &ply); //skip "end_header" at next line

	float a, b, c, d;	//for face lines and the 2nd line (that gives # of verts, faces, and edges) casting these to int will suffice
	float minX, minY, minZ, maxX, maxY, maxZ; //bbox to be used in center-of-bbox calculation
	mesh->minEdgeLen = INF;
	mesh->maxEdgeLen = -INF;
	mesh->edgeLenTotal = 0.0f;
	while (v++ < nVerts) //go till the end of file
	{
		if (mesh->frameID == 0)
			fscanf(fPtr, "%f %f %f %d %d %d\n", &a, &b, &c, &d, &d, &d); //last three are dummy 0's present only for frame 0
		else
			fscanf(fPtr, "%f %f %f\n", &a, &b, &c);

		//in original .off file, tri.areas ~= .1f and, e.g., split of them deceives >= .01f assertion in addTria wrongly
		a *= SCALE_FACTOR;	b *= SCALE_FACTOR;	c *= SCALE_FACTOR;

		//none of verts are removed/duplicated initially 'cos i read .ply
		float* coords = new float[3];
		coords[0] = a, coords[1] = b, coords[2] = c;
		mesh->addVertexND(coords); //ND: no duplicate check

		//bbox computation
		if ((int) mesh->verts.size() == 1)
		{
			minX = maxX = a;	minY = maxY = b;	minZ = maxZ = c;
		}
		else
		{
			if (a < minX)	minX = a; else if (a > maxX)	maxX = a;
			if (b < minY)	minY = b; else if (b > maxY)	maxY = b;
			if (c < minZ)	minZ = c; else if (c > maxZ)	maxZ = c;
		}
	}

	//verts ready, time to fill triangles
	while (fscanf(fPtr, "%f %f %f %f\n", &d, &a, &b, &c) != EOF) //go till the end of file
		mesh->addTriangle((int) a, (int) b, (int) c, true);

	float cobX = (minX+maxX) / 2.0f, cobY = (minY+maxY) / 2.0f, cobZ = (minZ+maxZ) / 2.0f;
	cout << "bbox.center: (" << cobX << ", " << cobY << ", " << cobZ << "); "
		 << "bbox.(w,h,d): (" << maxX-minX << ", " << maxY-minY << ", " << maxZ-minZ << ")\n"
		 << "min <= avg <= maxEdgeLen: " << mesh->minEdgeLen << " <= " << mesh->edgeLenTotal/((int) mesh->edges.size()) << " <= " << mesh->maxEdgeLen << "\n";
	fclose(fPtr);
	cout << "Initialization done\n\n";
}
