#include "stdafx.h"

#include "Mqo.h"
#include "MqoLoader.h"

#include "../BaseMesh.h"



namespace lib_geo
{


void MqoMesh::UpdateNormals(void)
{
	for( size_t i = 0 ; i < m_Normals.size() ; ++i )
	{
		m_Normals[i].set( 0.0f , 0.0f , 0.0f );
	}

	for( size_t i = 0 ; i < m_Faces.size() ; ++i )
	{
		MqoFace& f = m_Faces[i];
		for( size_t i = 0 ; i < f.NumTriangles() ; ++i )
		{
			size_t idx0 = f.m_VertexIdx[0];
			size_t idx1 = f.m_VertexIdx[i+1];
			size_t idx2 = f.m_VertexIdx[i+2];
			const MqoVector& v0 = m_Vertices[idx0];
			const MqoVector& v1 = m_Vertices[idx1];
			const MqoVector& v2 = m_Vertices[idx2];

			MqoVector n = cross( v2 - v0 , v1 - v0 );
			m_Normals[idx0] += n;
			m_Normals[idx1] += n;
			m_Normals[idx2] += n;
		}
	}

	for( size_t i = 0 ; i < m_Normals.size() ; ++i )
	{
		m_Normals[i].normalize();
	}
}


bool MqoObject::Load( const std::string& filename )
{
	MqoLoader loader;
	return loader.Load( *this , filename );
}


void MqoObject::ConvertToBaseMesh( BaseMesh& o_mesh )
{
	o_mesh.Clear();

	if( m_Meshs.empty() )
		return;

	std::vector<int> uv_per_obj( m_Meshs.size() , 0 );
	for( size_t i = 0 ; i < m_Meshs.size() ; ++i )
	{
		const MqoMesh& m = m_Meshs[i];

		for( size_t j = 0 ; j < m.m_Faces.size() ; ++j )
		{
			uv_per_obj[i] += (int)m.m_Faces[j].NumVertices();
		}
	}

	std::vector<int> ofs_v( m_Meshs.size() , 0 );
	std::vector<int> ofs_f( m_Meshs.size() , 0 );
	std::vector<int> ofs_n( m_Meshs.size() , 0 );
	std::vector<int> ofs_uv( m_Meshs.size() , 0 );
	for( size_t i = 1 ; i < m_Meshs.size() ; ++i )
	{
		const MqoMesh& m = m_Meshs[i-1];

		ofs_v[i] = ofs_v[i-1] + (int)m.m_Vertices.size();
		ofs_f[i] = ofs_f[i-1] + (int)m.m_Faces.size();
		ofs_n[i] = ofs_n[i-1] + (int)m.m_Normals.size();
		ofs_uv[i] = ofs_uv[i-1] + (int)uv_per_obj[i-1];
	}

	int num_v = ofs_v.back() + (int)m_Meshs.back().m_Vertices.size();
	int num_f = ofs_f.back() + (int)m_Meshs.back().m_Faces.size();
	int num_n = ofs_n.back() + (int)m_Meshs.back().m_Normals.size();
	int num_uv = ofs_uv.back() + (int)uv_per_obj.back();

	o_mesh.m_Verts.resize( num_v );
	o_mesh.m_Faces.resize( num_f );
	o_mesh.m_UVs.resize( num_uv );
	o_mesh.m_Normals.resize( num_n );
	for( size_t i = 0 ; i < m_Meshs.size() ; ++i )
	{
		const MqoMesh& m = m_Meshs[i];

		for( size_t j = 0 ; j < m.m_Vertices.size() ; ++j )
		{
			o_mesh.m_Verts[ ofs_v[i] + j ] = m.m_Vertices[j];
		}

		for( size_t j = 0 ; j < m.m_Normals.size() ; ++j )
		{
			o_mesh.m_Normals[ ofs_n[i] + j ] = m.m_Normals[j];
		}

		int added_uv = 0;
		for( size_t j = 0 ; j < m.m_Faces.size() ; ++j )
		{
			const MqoFace& mf = m.m_Faces[j];
			BaseFace& bf = o_mesh.m_Faces[ ofs_f[i] + j ];

			bf.m_VertIds.resize( mf.NumVertices() );
			bf.m_NormIds.resize( mf.NumVertices() );
			bf.m_UVIds.resize( mf.NumVertices() );
			for( size_t k = 0 ; k < mf.NumVertices() ; ++k )
			{
				bf.m_VertIds[k] = mf.m_VertexIdx[k] + ofs_v[i];
				bf.m_NormIds[k] = mf.m_VertexIdx[k] + ofs_v[i];
				bf.m_UVIds[k] = ofs_uv[i] + added_uv;
				added_uv++;

				o_mesh.m_UVs[ bf.m_UVIds[k] ] = mf.m_UV[k];
			}

			bf.m_MatIdx = mf.m_MaterialIdx;
		}
	}

	o_mesh.m_Materials.resize( m_Materials.size() );
	for( size_t i = 0 ; i < m_Materials.size() ; ++i )
	{
		const MqoMaterial& mm = m_Materials[i];
		lib_graph::Material& m = o_mesh.m_Materials[i];

		lib_graph::color4f c = mm.m_BaseColor;
		float a = mm.m_Ambient;
		float d = mm.m_Diffuse;
		float s = mm.m_Specular;
		float e = mm.m_Emission;
		float p = mm.m_Shininess;
		m.m_Ambient.set( a , a , a , c.a() );
		m.m_Diffuse.set( d * c.r() , d * c.g() , d * c.b() , c.a() );
		m.m_Specular.set( s , s , s , c.a() );
		m.m_Emission.set( e , e , e , c.a() );
		m.m_Shininess = s;
	}
}


}
