#include "precompile.h"
#include <fstream>
#include "mesh.h"

Mesh::~Mesh()
{
	m_vertices.clear();
	m_normals.clear();
	m_colors.clear();
	m_line_colors.clear();
	m_simulation_colors.clear();
	m_texcoords.clear();
	m_triangle_list.clear();
	m_user_data.clear();
	m_disconnected_vertices.clear();
}

// for data exchange with EigenLibrary
void Mesh::WriteToEigenVector3D(VectorX& v)
{
	unsigned int n = m_vertices.size();
	v.resize(3*n);
	for (unsigned i = 0; i != n; i++)
	{
		v.block_vector(i) = GLM2Eigen(m_vertices[i]);
	}
}
void Mesh::ReadFromEigenVector3D(const VectorX& v)
{
	unsigned int n = m_vertices.size();
	for (unsigned i = 0; i != n; i++)
	{
		m_vertices[i] = Eigen2GLM(v.block_vector(i));
	}
}
void Mesh::WriteToEigenVector2D(VectorX& v)
{
	unsigned int n = m_vertices.size();
	v.resize(2*n);
	for (unsigned i = 0; i != n; i++)
	{
		v[2*i+0] = m_vertices[i][0];
		v[2*i+1] = m_vertices[i][1];
	}
}
void Mesh::ReadFromEigenVector2D(const VectorX& v)
{
	unsigned int n = m_vertices.size();
	for (unsigned i = 0; i != n; i++)
	{
		m_vertices[i][0] = v[2*i+0];
		m_vertices[i][1] = v[2*i+1];
	}
}
void Mesh::ReadDisconnectedMeshFromEigenVector2D(const VectorX& v)
{
	unsigned int n = m_disconnected_vertices.size();
	for (unsigned i = 0; i != n; i++)
	{
		m_disconnected_vertices[i][0] = v[2*i+0];
		m_disconnected_vertices[i][1] = v[2*i+1];
	}
}

// for visualizing: functions
// update the normal per frame for visualization.
void Mesh::SetUniformColor(glm::vec3 color)
{
	for (unsigned int i = 0; i != m_vertices.size(); ++i)
	{
		m_colors[i] = color;
	}
}
void Mesh::SetUniformLineColor(glm::vec3 color)
{
	for (unsigned int i = 0; i != m_vertices.size(); ++i)
	{
		m_line_colors[i] = color;
	}
}
void Mesh::SetUniformSimulationColor(glm::vec3 color)
{
	for (unsigned int i = 0; i != m_vertices.size(); ++i)
	{
		m_simulation_colors[i] = color;
	}
}
void Mesh::ComputeNormal()
{
	// reset all the normal.
	glm::vec3 zero(0.0);
	for(std::vector<glm::vec3>::iterator n = m_normals.begin(); n != m_normals.end(); ++n)
	{
		*n = zero;
	}
	// calculate normal for each individual triangle
	unsigned int triangle_num = m_triangle_list.size() / 3;
	unsigned int id0, id1, id2;
	glm::vec3 p0, p1, p2;
	glm::vec3 normal;
	for(unsigned int i = 0; i < triangle_num; ++i)
	{
		id0 = m_triangle_list[3 * i];
		id1 = m_triangle_list[3 * i + 1];
		id2 = m_triangle_list[3 * i + 2];

		p0 = m_vertices[id0];
		p1 = m_vertices[id1];
		p2 = m_vertices[id2];

		normal = glm::cross((p1-p0), (p2-p1));
		glm::normalize(normal);

		m_normals[id0] += normal;
		m_normals[id1] += normal;
		m_normals[id2] += normal;
	}
	// re-normalize all the normals.
	for(std::vector<glm::vec3>::iterator n = m_normals.begin(); n != m_normals.end(); ++n)
	{
		if (glm::length(*n) > EPSILON) // skip if norm is a zero vector
			*n = glm::normalize(*n);
	}
}

void Mesh::Draw(const VBO& vbos, int show_texture)
{
	ComputeNormal();

	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

	unsigned int size = m_vertices.size();
	unsigned int element_num = m_triangle_list.size();

	// position
	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_vbo);
	glBufferData(GL_ARRAY_BUFFER, 3 * size * sizeof(float), &m_vertices[0], GL_DYNAMIC_DRAW);
	// color
	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_cbo);
	glBufferData(GL_ARRAY_BUFFER, 3 * size * sizeof(float), &m_colors[0], GL_STATIC_DRAW);
	// normal
	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_nbo);
	glBufferData(GL_ARRAY_BUFFER, 3 * size * sizeof(float), &m_normals[0], GL_DYNAMIC_DRAW);
	// texture
	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_tbo);
	glBufferData(GL_ARRAY_BUFFER, 2 * size * sizeof(float), &m_texcoords[0], GL_STATIC_DRAW);

	// indices
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos.m_ibo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, element_num * sizeof(unsigned int), &m_triangle_list[0], GL_STATIC_DRAW);

	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);
	glEnableVertexAttribArray(2);
	glEnableVertexAttribArray(3);

	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_vbo);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_cbo);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_nbo);
	glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_tbo);
	glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 0, 0);

	glm::mat4 identity = glm::mat4(); // identity matrix
	glUniformMatrix4fv(vbos.m_uniform_transformation, 1, false, &identity[0][0]);

	glUniform1i(vbos.m_uniform_enable_texture, show_texture); // enable/disable texture
	
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos.m_ibo);
	glDrawElements(GL_TRIANGLES, element_num, GL_UNSIGNED_INT, 0);

	glDisableVertexAttribArray(0);
	glDisableVertexAttribArray(1);
	glDisableVertexAttribArray(2);
	glDisableVertexAttribArray(3);
	glUniform1i(vbos.m_uniform_enable_texture, 0); // disable texture

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);	
}
void Mesh::DrawSimulationColor(const VBO& vbos, bool draw_disconnected_mesh)
{
	ComputeNormal();

	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

	unsigned int size = m_vertices.size();
	unsigned int element_num = m_triangle_list.size();

	std::vector<glm::vec3> positions;
	positions.clear();
	std::vector<unsigned int> triangles;
	triangles.clear();
	std::vector<glm::vec3> colors;
	colors.clear();
	std::vector<glm::vec3> normals;
	if (draw_disconnected_mesh)
	{
		for (unsigned int i = 0; i < element_num; i++)
		{
			triangles.push_back(i);
			normals.push_back(glm::vec3(0,0,1));
			normals.push_back(glm::vec3(0,0,1));
			normals.push_back(glm::vec3(0,0,1));
		}
		positions = m_disconnected_vertices;
		colors = m_disconnected_simulation_colors;
	}
	else
	{	
		colors = m_simulation_colors;
		positions = m_vertices;
		triangles = m_triangle_list;
		normals = m_normals;
	}

	// position
	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_vbo);
	glBufferData(GL_ARRAY_BUFFER, 3 * positions.size() * sizeof(float), &positions[0], GL_DYNAMIC_DRAW);
	// color
	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_cbo);
	glBufferData(GL_ARRAY_BUFFER, 3 * colors.size() * sizeof(float), &colors[0], GL_STATIC_DRAW);
	// normal
	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_nbo);
	glBufferData(GL_ARRAY_BUFFER, 3 * normals.size() * sizeof(float), &normals[0], GL_DYNAMIC_DRAW);

	// indices
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos.m_ibo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, element_num * sizeof(unsigned int), &triangles[0], GL_STATIC_DRAW);

	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);
	glEnableVertexAttribArray(2);

	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_vbo);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_cbo);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_nbo);
	glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glm::mat4 identity = glm::mat4(); // identity matrix
	glUniformMatrix4fv(vbos.m_uniform_transformation, 1, false, &identity[0][0]);

	glUniform1i(vbos.m_uniform_enable_texture, 0); // enable/disable texture

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos.m_ibo);
	glDrawElements(GL_TRIANGLES, element_num, GL_UNSIGNED_INT, 0);

	glDisableVertexAttribArray(0);
	glDisableVertexAttribArray(1);
	glDisableVertexAttribArray(2);
	glUniform1i(vbos.m_uniform_enable_texture, 0); // disable texture

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);	
}

void Mesh::DrawWireFrame(const VBO& vbos, bool draw_disconnected_mesh, int line_width)
{
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	glLineWidth(line_width);

	unsigned int size = m_vertices.size();
	unsigned int element_num = m_triangle_list.size();

	std::vector<glm::vec3> positions;
	positions.clear();
	std::vector<glm::vec3> line_colors;
	line_colors.clear();
	std::vector<unsigned int> triangles;
	triangles.clear();
	if (draw_disconnected_mesh)
	{
		for (unsigned int i = 0; i < element_num; i++)
		{
			line_colors.push_back(m_line_colors[m_triangle_list[i]]);
			triangles.push_back(i);
		}
		positions = m_disconnected_vertices;
		size = m_triangle_list.size();
	}
	else
	{
		positions = m_vertices;
		line_colors = m_line_colors;
		triangles = m_triangle_list;
	}


	// position and color 
	std::vector<glm::vec3> colors; colors.clear();
	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_vbo);
	glBufferData(GL_ARRAY_BUFFER, 3 * size * sizeof(float), &positions[0], GL_DYNAMIC_DRAW);

	// color
	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_cbo);
	glBufferData(GL_ARRAY_BUFFER, 3 * size * sizeof(float), &line_colors[0], GL_STATIC_DRAW);

	// indices
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos.m_ibo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, element_num * sizeof(unsigned int), &triangles[0], GL_STATIC_DRAW);

	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);

	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_vbo);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_cbo);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glm::mat4 identity = glm::mat4(); // identity matrix
	glUniformMatrix4fv(vbos.m_uniform_transformation, 1, false, &identity[0][0]);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos.m_ibo);
	glDrawElements(GL_TRIANGLES, element_num, GL_UNSIGNED_INT, 0);

	glDisableVertexAttribArray(0);
	glDisableVertexAttribArray(1);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);	
}

void Mesh::DrawUserData(const VBO& vbos, bool draw_disconnected_mesh)
{
	ComputeNormal();

	unsigned int size = m_vertices.size();
	unsigned int element_num = m_triangle_list.size();

	std::vector<glm::vec3> positions;
	positions.clear();
	std::vector<unsigned int> triangles;
	triangles.clear();
	if (draw_disconnected_mesh)
	{
		for (unsigned int i = 0; i < element_num; i++)
		{
			triangles.push_back(i);
		}
		positions = m_disconnected_vertices;
	}
	else
	{
		for (unsigned int i = 0; i < element_num; i++)
		{
			positions.push_back(m_vertices[m_triangle_list[i]]);
			triangles.push_back(i);
		}
	}

	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_vbo);
	glBufferData(GL_ARRAY_BUFFER, 3 * element_num * sizeof(float), &positions[0], GL_DYNAMIC_DRAW);

	// user data
	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_ubo);
	glBufferData(GL_ARRAY_BUFFER, element_num * sizeof(float), &m_user_data[0], GL_DYNAMIC_DRAW);

	// indices
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos.m_ibo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, element_num * sizeof(unsigned int), &triangles[0], GL_STATIC_DRAW);

	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(4);

	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_vbo);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glBindBuffer(GL_ARRAY_BUFFER, vbos.m_ubo);
	glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, 0, 0);

	glm::mat4 identity = glm::mat4(); // identity matrix
	glUniformMatrix4fv(vbos.m_uniform_transformation, 1, false, &identity[0][0]);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos.m_ibo);
	
	glDrawElements(GL_TRIANGLES, element_num, GL_UNSIGNED_INT, 0);

	glDisableVertexAttribArray(0);
	glDisableVertexAttribArray(4);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

void ObjMesh::ReadFromFile(char* filename, float scale)
{
	m_vertices.clear();
	m_texcoords.clear();
	m_faces.clear();
	m_triangle_list.clear();
	
	m_load_success = false;

	bool uv_read_from_file = false;

	std::ifstream infile(filename);
	if(!infile.good())
	{
		printf("Error in loading file %s\n", filename);
	}
	char buffer[256];
	unsigned int ip0, ip1, ip2;
	unsigned int n0, n1, n2;
	unsigned int t0, t1, t2;
	glm::vec3 pos;
	glm::vec2 uv;

	while(!infile.getline(buffer,255).eof())
	{
		buffer[255] = '\0';
		if(buffer[0] == 'v' && (buffer[1] == ' ' || buffer[1] == 32))
		{
			if(sscanf_s(buffer, "v %f %f %f", &pos.x, &pos.y, &pos.z) == 3)
			{
				pos = scale * pos;
				m_vertices.push_back(pos);
			}
			else
			{
				printf("Vertex is not in desired format.\n");
				exit(0);
			}
		}
		else if (buffer[0] == 'v' && buffer[1] == 'n' && (buffer[2] == ' ' || buffer[2] == 32))
		{
			// load normals from obj file.
		}
		else if (buffer[0] == 'v' && buffer[1] == 't' && (buffer[2] == ' ' || buffer[2] == 32))
		{
			// load uv coordinates
			if(sscanf_s(buffer, "vt %f %f", &uv.x, &uv.y) == 2)
			{
				//uv.y = 1-uv.y;
				m_texcoords.push_back(uv);
				uv_read_from_file = true;
			}
			else
			{
				printf("UV is not in desired format.\n");
				exit(0);
			}
		}
		else if (buffer[0] == 'f' && (buffer[1] == ' ' || buffer[1] == 32))
		{
			if(sscanf_s(buffer, "f %u %u %u", &ip0, &ip1, &ip2) == 3)
			{
				m_triangle_list.push_back(--ip0);
				m_triangle_list.push_back(--ip1);
				m_triangle_list.push_back(--ip2);
				m_faces.push_back(Face(ip0, ip1, ip2));
			}
			else if(sscanf_s(buffer, "f %u//%u %u//%u %u//%u", &ip0, &n0, &ip1, &n1, &ip2, &n2) == 6)
			{
				m_triangle_list.push_back(--ip0);
				m_triangle_list.push_back(--ip1);
				m_triangle_list.push_back(--ip2);
				m_faces.push_back(Face(ip0, ip1, ip2));
			}
			else if(sscanf_s(buffer, "f %u/%u %u/%u %u/%u", &ip0, &n0, &ip1, &n1, &ip2, &n2) == 6)
			{
				m_triangle_list.push_back(--ip0);
				m_triangle_list.push_back(--ip1);
				m_triangle_list.push_back(--ip2);
				m_faces.push_back(Face(ip0, ip1, ip2));
			}
			else if(sscanf_s(buffer, "f %u//%u//%u %u//%u//%u %u//%u//%u", &ip0, &n0, &t0, &ip1, &n1, &t1, &ip2, &n2, &t2) == 9)
			{
				m_triangle_list.push_back(--ip0);
				m_triangle_list.push_back(--ip1);
				m_triangle_list.push_back(--ip2);
				m_faces.push_back(Face(ip0, ip1, ip2));
			}
			else if(sscanf_s(buffer, "f %u/%u/%u %u/%u/%u %u/%u/%u", &ip0, &n0, &t0, &ip1, &n1, &t1, &ip2, &n2, &t2) == 9)
			{
				m_triangle_list.push_back(--ip0);
				m_triangle_list.push_back(--ip1);
				m_triangle_list.push_back(--ip2);
				m_faces.push_back(Face(ip0, ip1, ip2));
			}
			else
			{
				printf("Triangle indices is not in desired format.\n");
			}
		}
	}

	unsigned int n = m_vertices.size();
	m_normals.resize(n);
	m_colors.resize(n);
	m_line_colors.resize(n);
	m_simulation_colors.resize(n);
	if (!uv_read_from_file)
		m_texcoords.resize(n);
	m_user_data.resize(m_triangle_list.size());
	m_disconnected_vertices.resize(m_triangle_list.size());
	m_disconnected_simulation_colors.resize(m_triangle_list.size());
	for (unsigned int i = 0; i != m_triangle_list.size(); ++i)
	{
		m_user_data[i] = 0;
		m_disconnected_vertices[i] = m_vertices[m_triangle_list[i]];
	}

	SetUniformColor();
	SetUniformLineColor();
	SetUniformSimulationColor();

	m_load_success = true;
}

void ObjMesh::WriteToFile(char* filename)
{
	std::ofstream outfile;
	outfile.open(filename, std::ifstream::out);
	if (outfile.is_open())
	{
		outfile << "//#vertices: " << m_vertices.size() << std::endl;
		for (unsigned int i = 0; i < m_vertices.size(); i++)
		{
			// save positions
			outfile << "v " << m_vertices[i][0] << " " << m_vertices[i][1] << " " << m_vertices[i][2] << std::endl;
		}

		outfile << "//#faces: " << m_triangle_list.size()/3 << std::endl;
		for (unsigned int f = 0; f < m_triangle_list.size(); f += 3)
		{
			outfile << "f " << m_triangle_list[f + 0] + 1 << " " << m_triangle_list[f + 1] + 1 << " " << m_triangle_list[f + 2] + 1 << std::endl;
		}

		outfile.close();
	}
}

void ObjMesh::GetMeshInfo(char* info)
{
	sprintf(info, "#Verts: %d | #Tris: %d", m_vertices.size(), m_faces.size());
}

void ObjMesh::WriteToSimulation(VectorX& v)
{
	WriteToEigenVector2D(v);
}
void ObjMesh::WriteToSimulation(EigenMatrix& v)
{
	unsigned int n = m_vertices.size();
	v.resize(n, 3);
	for (unsigned i = 0; i != n; i++)
	{
		v(i, 0) = m_vertices[i][0];
		v(i, 1) = m_vertices[i][1];
		v(i, 2) = 1.0;
	}
}
void ObjMesh::ReadFromSimulation(const VectorX& v)
{
	ReadFromEigenVector2D(v);
}
std::vector<unsigned int> ObjMesh::GetElementId(unsigned int i)
{
	assert(i < m_faces.size());
	
	std::vector<unsigned int> ids;
	ids.clear();
	Face& f = m_faces[i];

	ids.push_back(f.id1);
	ids.push_back(f.id2);
	ids.push_back(f.id3);

	return ids;
}


void MeshMesh::ReadFromFile(char* filename, float scale)
{
	m_vertices.clear();
	m_faces.clear();
	m_tets.clear();
	m_triangle_list.clear();

	m_load_success = false;

	std::cout << "MeshIO initializing (to " << filename << ").." << std::endl;

	std::ifstream infile(filename);
	if(!infile.is_open())
	{
		std::cout << "cannot read " << filename << std::endl;
		return;
	}

	char buffer[256];
	glm::vec3 pos;
	Face face; 
	Tet tet; 
	char ignore[256];
	while(!infile.eof())
	{
		infile >> buffer;
		if (strcmp(buffer, "Vertices") == 0)
		{
			int num_vertices;
			infile >> num_vertices;
			for (int i = 0; i < num_vertices; i++)
			{
				infile >> pos.x >> pos.y >> pos.z >> ignore;
				//if (flip) pos.y *= -1;
				m_vertices.push_back(pos * scale);
			}
			if (m_vertices.size() != num_vertices)
			{
				std::cout << "Init MeshLoader: error on reading vertices." << std::endl;
				return;
			}
		}
		else if (strcmp(buffer, "Triangles") == 0)
		{
			int num_face;
			infile >> num_face;
			for (int i = 0; i < num_face; i++)
			{
				infile >> face.id1 >> face.id2 >> face.id3 >> ignore;
				face.IDMinusMinus();
				m_triangle_list.push_back(face.id1);
				m_triangle_list.push_back(face.id2);
				m_triangle_list.push_back(face.id3);
				m_faces.push_back(face);
			}
			if (m_faces.size() != num_face)
			{
				std::cout << "Init MeshLoader: error on reading faces." << std::endl;
				return;
			}
		}
		else if (strcmp(buffer, "Tetrahedra") == 0)
		{
			int num_tet;
			infile >> num_tet;
			for (int i = 0; i < num_tet; i++)
			{
				infile >> tet.id1 >> tet.id2 >> tet.id3 >> tet.id4 >> ignore;
				tet.IDMinusMinus();
				m_tets.push_back(tet);
			}
			if (m_tets.size() != num_tet)
			{
				std::cout << "Init MeshLoader: error on reading tets." << std::endl;
				return;
			}
		}
	}

	unsigned int n = m_vertices.size();
	m_normals.resize(n);
	m_colors.resize(n);
	m_line_colors.resize(n);
	m_simulation_colors.resize(n);
	m_texcoords.resize(n);
	m_user_data.resize(m_triangle_list.size());
	m_disconnected_vertices.resize(m_triangle_list.size());
	m_disconnected_simulation_colors.resize(m_triangle_list.size());
	for (unsigned int i = 0; i != m_triangle_list.size(); ++i)
	{
		m_user_data[i] = 0;
		m_disconnected_vertices[i] = m_vertices[m_triangle_list[i]];
	}

	SetUniformColor();
	SetUniformLineColor();

	m_load_success = true;
}

void MeshMesh::WriteToFile(char* filename)
{
	// TODO: export to .mesh
}

void MeshMesh::GetMeshInfo(char* info)
{
	sprintf(info, "#Verts: %d | #Tets: %d", m_vertices.size(), m_tets.size());
}

void MeshMesh::WriteToSimulation(VectorX& v)
{
	WriteToEigenVector3D(v);
}
void MeshMesh::WriteToSimulation(EigenMatrix& v)
{
	unsigned int n = m_vertices.size();
	v.resize(n, 4);
	for (unsigned i = 0; i != n; i++)
	{
		v(i, 0) = m_vertices[i][0];
		v(i, 1) = m_vertices[i][1];
		v(i, 2) = m_vertices[i][2];
		v(i, 3) = 1.0;
	}
}
void MeshMesh::ReadFromSimulation(const VectorX& v)
{
	ReadFromEigenVector3D(v);
}
std::vector<unsigned int> MeshMesh::GetElementId(unsigned int i)
{
	assert(i < m_tets.size());

	std::vector<unsigned int> ids;
	ids.clear();
	Tet& t = m_tets[i];

	ids.push_back(t.id1);
	ids.push_back(t.id2);
	ids.push_back(t.id3);
	ids.push_back(t.id4);

	return ids;
}

