#include "stdafx.h"

#include <map>
#include <set>

#include "BaseMesh.h"

#include "../Algorithm/Geom3d.h"



namespace lib_geo
{


// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// BaseMesh

//! 全バッファをクリア
void BaseMesh::Clear(void)
{
	m_Verts.clear();
	m_Normals.clear();
	m_UVs.clear();
	m_Tangents.clear();

	m_Faces.clear();
	m_Edges.clear();
	m_Polylines.clear();

	m_Materials.clear();
}


bool BaseMesh::HasNormal(void) const
{
	return !m_Normals.empty();
}

bool BaseMesh::HasUV(void) const
{
	return !m_UVs.empty();
}

bool BaseMesh::HasEdge(void) const
{
	return !m_Edges.empty();
}

bool BaseMesh::HasVertAdj(void) const
{
	return !m_VertAdj.empty();
}

bool BaseMesh::HasTangent(void) const
{
	return !m_Tangents.empty();
}


//! 1頂点1法線となるように法線バッファを生成する
void BaseMesh::CreateNormalsEachVerts(void)
{
	m_Normals.clear();
	m_Normals.resize( m_Verts.size() );

	for( size_t i = 0 ; i < m_Faces.size() ; ++i )
	{
		BaseFace& f = m_Faces[i];
		f.m_NormIds = f.m_VertIds;
	}
}

//! 法線を更新する
void BaseMesh::UpdateNormal(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 )
	{
		const BaseFace& f = m_Faces[i];
		if( !f.HasNormal() )
			continue;

		for( size_t j = 0 ; j < f.NumTriangles() ; ++j )
		{
			const lm::vec3f& v0 = m_Verts[ f.m_VertIds[0  ] ];
			const lm::vec3f& v1 = m_Verts[ f.m_VertIds[j+1] ];
			const lm::vec3f& v2 = m_Verts[ f.m_VertIds[j+2] ];
			lm::vec3f& n0 = m_Normals[ f.m_NormIds[0  ] ];
			lm::vec3f& n1 = m_Normals[ f.m_NormIds[j+1] ];
			lm::vec3f& n2 = m_Normals[ f.m_NormIds[j+2] ];

			lm::vec3f n = cross( v1 - v0 , v2 - v0 );
			n0 += n;
			n1 += n;
			n2 += n;
		}
	}

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


//! ポリゴンの構造からエッジバッファを生成する
void BaseMesh::CreateEdgeFromFace(void)
{
	m_Edges.clear();

	std::vector< std::set<int> > VertLinks( m_Verts.size() );
	for( size_t i = 0 ; i < m_Faces.size() ; ++i )
	{
		const BaseFace& f = m_Faces[i];
		for( size_t j = 0 ; j < f.NumVertices() ; ++j )
		{
			int edge_vid0 = f.m_VertIds[ j ];
			int edge_vid1 = f.m_VertIds[ (j+1) % f.NumVertices() ];
			if( edge_vid0 > edge_vid1 )
				std::swap( edge_vid0 , edge_vid1 );

			VertLinks[edge_vid0].insert( edge_vid1 );
		}
	}

	for( size_t i = 0 ; i < VertLinks.size() ; ++i )
	{
		for( std::set<int>::iterator iter = VertLinks[i].begin() ; iter != VertLinks[i].end() ; ++iter )
		{
			BaseEdge e;
			e.m_VertIds[0] = (int)i;
			e.m_VertIds[1] = *iter;
			m_Edges.push_back( e );
		}
	}
}

void BaseMesh::CreateTangentsByUV(void)
{
	m_Tangents.clear();
	m_Tangents.resize(m_UVs.size(), lm::vec3f::get_zero());

	for(size_t i = 0; i < m_Faces.size(); ++i)
	{
		const lib_geo::BaseFace& f = m_Faces[i];

		if( !f.HasUV() )
			continue;

		size_t polygon_size = f.m_UVIds.size();

		for(size_t j = 0; j < polygon_size; ++j)
		{
			size_t idx0 = j;
			size_t idx1 = (j+1) % polygon_size;

			int uvid0 = f.m_UVIds[idx0];
			int uvid1 = f.m_UVIds[idx1];
			int vid0 = f.m_VertIds[idx0];
			int vid1 = f.m_VertIds[idx1];
			int nid0 = f.m_NormIds[idx0];

			lm::vec3f& p0 = m_Verts[vid0];
			lm::vec3f& p1 = m_Verts[vid1];
			lm::vec2f& uv0 = m_UVs[uvid0];
			lm::vec2f& uv1 = m_UVs[uvid1];

			lm::vec2f d_2d = (uv1 - uv0).get_normalize();

			lm::vec3f& nrm_3d = m_Normals[nid0];
			lm::vec3f tan_3d = (p1 - p0).get_normalize();
			lm::vec3f bin_3d = lm::cross(tan_3d, nrm_3d).get_normalize();
			tan_3d = lm::cross(nrm_3d, bin_3d).get_normalize();

			lm::vec3f dst_t = tan_3d * d_2d.x + bin_3d * d_2d.y;

			m_Tangents[uvid0] += dst_t;
		}
	}

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

void BaseMesh::ClearAdjBuffer(void)
{
	m_VertAdj.clear();
	m_VertAdj.resize(m_Verts.size());

	for( size_t i = 0 ; i < m_Edges.size() ; ++i )
		m_Edges[i].ClearAdjBuffer();

	for( size_t i = 0 ; i < m_Faces.size() ; ++i )
		m_Faces[i].ClearAdjBuffer();
}

//! 各種隣接情報の再生成
void BaseMesh::CreateAdjBuffers(void)
{
	ClearAdjBuffer();

	for( size_t i = 0 ; i < m_Faces.size() ; ++i )
	{
		BaseFace& f = m_Faces[i];
			int fid = (int)i;

		for( size_t j = 0 ; j < f.m_VertIds.size() ; ++j )
		{
			m_VertAdj[ f.m_VertIds[j] ].m_AdjFids.push_back( fid );
		}
	}

	if(!m_Edges.empty())
	{
		std::map< std::pair<int,int> , int > EidMap;

		for( size_t i = 0 ; i < m_Edges.size() ; ++i )
		{
			BaseEdge& e = m_Edges[i];
			int eid = (int)i;

			int vid0 = e.m_VertIds[0];
			int vid1 = e.m_VertIds[1];

			if( vid0 >= 0 )
				m_VertAdj[vid0].m_AdjEids.push_back( eid );
			if( vid1 >= 0 )
				m_VertAdj[vid1].m_AdjEids.push_back( eid );

			if( vid0 > vid1 ) std::swap( vid0 , vid1 );
			EidMap[ e.ToIntPair() ] = eid;
		}

		for( size_t i = 0 ; i < m_Faces.size() ; ++i )
		{
			BaseFace& f = m_Faces[i];
			int fid = (int)i;

			size_t NumFaceVerts = f.m_VertIds.size();
			for( size_t j = 0 ; j < NumFaceVerts ; ++j )
			{
				int vid0 = f.m_VertIds[j];
				int vid1 = f.m_VertIds[(j + 1) % NumFaceVerts];
				if(vid0 > vid1)
					std::swap(vid0, vid1);

				int eid = EidMap[ std::pair<int, int>(vid0, vid1) ];

				f.m_AdjEids.push_back(eid);

				m_Edges[eid].m_AdjFids.push_back(fid);
			}
		}
	}

	UpdateAdjVertNormal();
}

void BaseMesh::UpdateAdjVertNormal(void)
{
	for( size_t i = 0 ; i < m_VertAdj.size() ; ++i )
	{
		m_VertAdj[i].m_NormalAvg.set(0.0f, 0.0f, 0.0f);
	}

	for( size_t i = 0 ; i < m_Faces.size() ; ++i )
	{
		const BaseFace& f = m_Faces[i];
		for( size_t j = 0 ; j < f.NumTriangles() ; ++j )
		{
			int vid0 = f.m_VertIds[0];
			int vid1 = f.m_VertIds[j+1];
			int vid2 = f.m_VertIds[j+2];

			const lm::vec3f& v0 = m_Verts[vid0];
			const lm::vec3f& v1 = m_Verts[vid1];
			const lm::vec3f& v2 = m_Verts[vid2];

			lm::vec3f n = cross( v1 - v0 , v2 - v0 );
			m_VertAdj[vid0].m_NormalAvg += n;
			m_VertAdj[vid1].m_NormalAvg += n;
			m_VertAdj[vid2].m_NormalAvg += n;
		}
	}

	for( size_t i = 0 ; i < m_VertAdj.size() ; ++i )
	{
		lm::vec3f& n = m_VertAdj[i].m_NormalAvg;
		if(!n.is_zero())
			n.normalize();
	}
}

void BaseMesh::CreateUVsEachVerts(void)
{
	m_UVs.assign(m_Verts.size(), lm::vec2f::get_zero());
	for(size_t i = 0; i < m_Faces.size(); ++i)
	{
		BaseFace& f = m_Faces[i];
		f.m_UVIds = f.m_VertIds;
	}
}

//! AABBを求める
lm::range3f BaseMesh::CalcAABB(void) const
{
	lm::range3f aabb;
	aabb.clear();

	for( size_t i = 0 ; i < m_Verts.size() ; ++i )
	{
		aabb.expand( m_Verts[i] );
	}

	return aabb;
}


//! 全ポリゴンを三角化する.
void BaseMesh::Triangulate(void)
{
	size_t TotalTriangles = 0;
	for( size_t i = 0 ; i < m_Faces.size() ; ++i )
	{
		TotalTriangles += m_Faces[i].NumTriangles();
	}

	if( TotalTriangles == m_Faces.size() )
		return;

	std::vector<BaseFace> NewFaces;
	NewFaces.reserve(TotalTriangles);
	for( size_t i = 0 ; i < m_Faces.size() ; ++i )
	{
		BaseFace& f = m_Faces[i];
		if( f.NumTriangles() == 1 )
		{
			NewFaces.push_back(f);
		}
		else
		{
			for( size_t j = 0 ; j < f.NumTriangles() ; ++j )
			{
				int sub_vid0 = 0;
				int sub_vid1 = (int)j+1;
				int sub_vid2 = (int)j+2;

				BaseFace new_face;
				new_face.m_MatIdx = f.m_MatIdx;

				new_face.m_VertIds.resize(3);
				new_face.m_VertIds[0] = f.m_VertIds[sub_vid0];
				new_face.m_VertIds[1] = f.m_VertIds[sub_vid1];
				new_face.m_VertIds[2] = f.m_VertIds[sub_vid2];

				if( !f.m_NormIds.empty() )
				{
					new_face.m_NormIds.resize(3);
					new_face.m_NormIds[0] = f.m_NormIds[sub_vid0];
					new_face.m_NormIds[1] = f.m_NormIds[sub_vid1];
					new_face.m_NormIds[2] = f.m_NormIds[sub_vid2];
				}

				if( !f.m_UVIds.empty() )
				{
					new_face.m_UVIds.resize(3);
					new_face.m_UVIds[0] = f.m_UVIds[sub_vid0];
					new_face.m_UVIds[1] = f.m_UVIds[sub_vid1];
					new_face.m_UVIds[2] = f.m_UVIds[sub_vid2];
				}

				NewFaces.push_back( new_face );
			}
		}
	}

	m_Faces.swap(NewFaces);

	if(HasEdge())
		CreateEdgeFromFace();

	if(HasVertAdj())
		CreateAdjBuffers();
}


//! 未使用頂点バッファを切り詰める.
void BaseMesh::RemoveNotReferencedVertex(void)
{
	// TODO : m_Tangentは未対応

	std::vector<bool> VertRef, NormalRef, UVRef;
	GetReferencedVertMap(VertRef, NormalRef, UVRef);

	size_t VidCount = 0;
	std::vector<int> NewVertIdx( m_Verts.size() , -1 );
	for( size_t i = 0 ; i < VertRef.size() ; ++i )
	{
		if( VertRef[i] )
			NewVertIdx[i] = (int)VidCount++;
	}

	size_t NidCount = 0;
	std::vector<int> NewNormalIdx( m_Normals.size() , -1 );
	for( size_t i = 0 ; i < NormalRef.size() ; ++i )
	{
		if( NormalRef[i] )
			NewNormalIdx[i] = (int)NidCount++;
	}

	size_t UidCount = 0;
	std::vector<int> NewUVIdx( m_UVs.size() , -1 );
	for( size_t i = 0 ; i < UVRef.size() ; ++i )
	{
		if( UVRef[i] )
			NewUVIdx[i] = (int)UidCount++;
	}

	if( VidCount != m_Verts.size() )
	{
		for( size_t i = 0 ; i < NewVertIdx.size() ; ++i )
		{
			int idx = NewVertIdx[i];
			if( idx < 0 || (int)i == idx )
				continue;

			m_Verts[idx] = m_Verts[i];
		}
		m_Verts.resize(VidCount);
	}

	if( NidCount != m_Normals.size() )
	{
		for( size_t i = 0 ; i < NewNormalIdx.size() ; ++i )
		{
			int idx = NewNormalIdx[i];
			if( idx < 0 || (int)i == idx )
				continue;

			m_Normals[idx] = m_Normals[i];
		}
		m_Normals.resize(NidCount);
	}

	if( UidCount != m_UVs.size() )
	{
		for( size_t i = 0 ; i < NewUVIdx.size() ; ++i )
		{
			int idx = NewUVIdx[i];
			if( idx < 0 || (int)i == idx )
				continue;

			m_UVs[idx] = m_UVs[i];
		}
		m_UVs.resize(UidCount);
	}

	for( size_t i = 0 ; i < m_Faces.size() ; ++i )
	{
		BaseFace& face = m_Faces[i];
		for( size_t j = 0 ; j < face.m_VertIds.size() ; ++j )
		{
			face.m_VertIds[j] = NewVertIdx[ face.m_VertIds[j] ];
		}

		for( size_t j = 0 ; j < face.m_NormIds.size() ; ++j )
		{
			face.m_NormIds[j] = NewNormalIdx[ face.m_NormIds[j] ];
		}

		for( size_t j = 0 ; j < face.m_UVIds.size() ; ++j )
		{
			face.m_UVIds[j] = NewUVIdx[ face.m_UVIds[j] ];
		}
	}

	for( size_t i = 0 ; i < m_Edges.size() ; ++i )
	{
		BaseEdge& edge = m_Edges[i];
		edge.m_VertIds[0] = NewVertIdx[ edge.m_VertIds[0] ];
		edge.m_VertIds[1] = NewVertIdx[ edge.m_VertIds[1] ];
	}

	for( size_t i = 0; i < m_Polylines.size(); ++i )
	{
		BasePolyline& pl = m_Polylines[i];
		for( size_t j = 0; j < pl.m_VertIds.size(); ++j )
		{
			int& vid = pl.m_VertIds[j];
			vid = NewVertIdx[ vid ];
		}
	}
}

// 修正前のメッシュで使用されていた頂点を求める
void BaseMesh::GetReferencedVertMap(std::vector<bool>& VertRef, std::vector<bool>& NormalRef, std::vector<bool>& UVRef) const
{
	VertRef.resize( m_Verts.size() , false );
	NormalRef.resize( m_Normals.size() , false );
	UVRef.resize( m_UVs.size() , false );

	for( size_t i = 0 ; i < m_Faces.size() ; ++i )
	{
		const BaseFace& face = m_Faces[i];

		for( size_t j = 0 ; j < face.m_VertIds.size() ; ++j )
		{
			VertRef[ face.m_VertIds[j] ] = true;
		}

		for( size_t j = 0 ; j < face.m_NormIds.size() ; ++j )
		{
			NormalRef[ face.m_NormIds[j] ] = true;
		}

		for( size_t j = 0 ; j < face.m_UVIds.size() ; ++j )
		{
			UVRef[ face.m_UVIds[j] ] = true;
		}
	}

	for( size_t i = 0; i < m_Polylines.size(); ++i )
	{
		const BasePolyline& pl = m_Polylines[i];
		for( size_t j = 0; j < pl.m_VertIds.size(); ++j )
		{
			VertRef[ pl.m_VertIds[j] ] = true;
		}
	}
}


//! 隣接頂点の結合
void BaseMesh::RemDoubleVertex(void)
{
	// 実装中	
}


void BaseMesh::Translate( const lm::vec3f& v )
{
	for( size_t i = 0 ; i < m_Verts.size() ; ++i )
		m_Verts[i] += v;
}

void BaseMesh::Translate( float x , float y , float z )
{
	for( size_t i = 0 ; i < m_Verts.size() ; ++i )
	{
		lm::vec3f& v = m_Verts[i];
		v.set( v.x + x , v.y + y , v.z + z );
	}
}

void BaseMesh::Scale( float s )
{
	for( size_t i = 0 ; i < m_Verts.size() ; ++i )
		m_Verts[i] *= s;
}

void BaseMesh::Scale( float sx , float sy , float sz )
{
	for( size_t i = 0 ; i < m_Verts.size() ; ++i )
	{
		lm::vec3f& v = m_Verts[i];
		v.set( v.x * sx , v.y * sy , v.z * sz );
	}
}

void BaseMesh::RotateX( float angle )
{
	for( size_t i = 0 ; i < m_Verts.size() ; ++i )
		m_Verts[i].rotate_x(angle);
}

void BaseMesh::RotateY( float angle )
{
	for( size_t i = 0 ; i < m_Verts.size() ; ++i )
		m_Verts[i].rotate_y(angle);
}

void BaseMesh::RotateZ( float angle )
{
	for( size_t i = 0 ; i < m_Verts.size() ; ++i )
		m_Verts[i].rotate_z(angle);
}

void BaseMesh::Rotate( const lm::vec3f& axis , float angle )
{
	for( size_t i = 0 ; i < m_Verts.size() ; ++i )
		m_Verts[i].rotate(angle, axis);
}


size_t BaseMesh::NumTriangles(void) const
{
	size_t n = 0;
	for(size_t i = 0; i < m_Faces.size(); ++i)
	{
		n += m_Faces[i].NumTriangles();
	}

	return n;
}


void BaseMesh::CalcNormalEachVerts(std::vector<lm::vec3f>& normals) const
{
	normals.clear();
	normals.resize( m_Verts.size() , lm::vec3f(0.0f, 0.0f, 0.0f) );

	for( size_t i = 0 ; i < m_Faces.size() ; ++i )
	{
		const BaseFace& f = m_Faces[i];
		for( size_t j = 0 ; j < f.NumTriangles() ; ++j )
		{
			int vid0 = f.m_VertIds[0  ];
			int vid1 = f.m_VertIds[j+1];
			int vid2 = f.m_VertIds[j+2];
			const lm::vec3f& v0 = m_Verts[vid0];
			const lm::vec3f& v1 = m_Verts[vid1];
			const lm::vec3f& v2 = m_Verts[vid2];

			lm::vec3f n = cross(v1 - v0, v2 - v0);
			normals[vid0] += n;
			normals[vid1] += n;
			normals[vid2] += n;
		}
	}

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


lm::vec3f BaseMesh::GetFaceCenter(const size_t face_idx) const
{
	return GetFaceCenter(m_Faces[face_idx]);
}

lm::vec3f BaseMesh::GetFaceCenter(const BaseFace& f) const
{
	lm::vec3f c(0.0f, 0.0f, 0.0f);
	for (size_t j = 0; j < f.m_VertIds.size(); ++j)
	{
		c += m_Verts[f.m_VertIds[j]];
	}

	c /= (float)f.m_VertIds.size();

	return c;
}

lm::vec3f BaseMesh::GetFaceNormal(const BaseFace& f) const
{
	lm::vec3f n(0.0f, 0.0f, 0.0f);
	for (size_t i = 0; i < f.NumTriangles(); ++i)
	{
		const lm::vec3f& n0 = m_Verts[f.m_VertIds[0]];
		const lm::vec3f& n1 = m_Verts[f.m_VertIds[i+1]];
		const lm::vec3f& n2 = m_Verts[f.m_VertIds[i+2]];
		n += cross(n1 - n0, n2 - n0);
	}

	return n.get_normalize();
}


void BaseMesh::MergeLinkedPolylines(void)
{
	for(;;)
	{
		bool updated = false;

		for(size_t i = 0; i < m_Polylines.size(); ++i)
		{
			for(size_t j = i + 1; j < m_Polylines.size(); ++j)
			{
				BasePolyline& p0 = m_Polylines[i];
				BasePolyline& p1 = m_Polylines[j];

				if(p0.m_VertIds.back() == p1.m_VertIds.front())
				{
				}
				else if(p0.m_VertIds.back() == p1.m_VertIds.back())
				{
					std::reverse(p1.m_VertIds.begin(), p1.m_VertIds.end());
				}
				else if(p0.m_VertIds.front() == p1.m_VertIds.front())
				{
					std::reverse(p0.m_VertIds.begin(), p0.m_VertIds.end());
				}
				else if(p0.m_VertIds.front() == p1.m_VertIds.back())
				{
					std::reverse(p0.m_VertIds.begin(), p0.m_VertIds.end());
					std::reverse(p1.m_VertIds.begin(), p1.m_VertIds.end());
				}
				else
				{
					continue;
				}

				for(size_t k = 1; k < p1.m_VertIds.size(); ++k)
				{
					p0.m_VertIds.push_back(p1.m_VertIds[k]);
				}

				m_Polylines.back().Swap(p1);
				m_Polylines.pop_back();

				--j;
				updated = true;
			}
		}

		if(!updated)
			break;
	}
}


bool BaseMesh::GetClosestSubfacePos(const lm::vec3f& pos, int& fid, int& subface, lm::vec3f& close_pos) const
{
	fid = -1;
	subface = -1;
	close_pos.set(0.0f, 0.0f, 0.0f);
	float close_dsq = (std::numeric_limits<float>::max)();

	for (size_t i = 0; i < m_Faces.size(); ++i)
	{
		const BaseFace& f = m_Faces[i];
		size_t num_t = f.NumTriangles();
		for (size_t j = 0; j < num_t; ++j)
		{
			const lm::vec3f& v0 = m_Verts[f.m_VertIds[0]];
			const lm::vec3f& v1 = m_Verts[f.m_VertIds[1 + j]];
			const lm::vec3f& v2 = m_Verts[f.m_VertIds[2 + j]];

			lm::vec3f cp = Geom3d::Closest_Triangle_Point(v0, v1, v2, pos);
			float dsq = (cp - pos).square_length();
			if (dsq < close_dsq)
			{
				close_dsq = dsq;
				fid = (int)i;
				subface = (int)j;
				close_pos = cp;
			}
		}
	}

	return (fid != -1 && subface != -1);
}

bool BaseMesh::CalcBaryCoordMain(const lm::vec3f& pos, size_t fid, size_t subface, float& u, float& v, float& w) const
{
	assert(fid < m_Faces.size());
	if (fid > m_Faces.size())
		return false;

	const BaseFace& f = m_Faces[fid];
	assert(subface < f.NumTriangles());
	if (subface >= f.NumTriangles())
		return false;

	const lm::vec3f& v0 = m_Verts[f.m_VertIds[0]];
	const lm::vec3f& v1 = m_Verts[f.m_VertIds[subface + 1]];
	const lm::vec3f& v2 = m_Verts[f.m_VertIds[subface + 2]];

	lm::vec3f vp0 = pos - v0;
	lm::vec3f vp1 = pos - v1;
	lm::vec3f vp2 = pos - v2;
	lm::vec3f refN = cross(v1 - v0, v2 - v0).get_normalize();

	u = dot(cross(vp1, vp2), refN);
	v = dot(cross(vp2, vp0), refN);
	w = dot(cross(vp0, vp1), refN);

	float t = u + v + w;
	if (t <= 0.0f)
	{
		u = 1.0f / 3.0f;
		v = 1.0f / 3.0f;
		w = 1.0f / 3.0f;
	}
	else
	{
		u /= t;
		v /= t;
		w /= t;
	}

	return true;
}

bool BaseMesh::CalcBaryCoord(const lm::vec3f& pos, size_t fid, size_t subface, float& u, float& v, float& w) const
{
	return CalcBaryCoordMain(pos, fid, subface, u, v, w);
}

bool BaseMesh::CalcBaryCoord(const lm::vec3f& pos, size_t fid, size_t subface, lm::vec3f& bc) const
{
	return CalcBaryCoordMain(pos, fid, subface, bc.x, bc.y, bc.z);
}

bool BaseMesh::CalcBaryCoord(const lm::vec3f& pos, size_t fid, size_t subface, BaryCoord& bc) const
{
	bc.Reset();

	if (!CalcBaryCoordMain(pos, fid, subface, bc.Bary.x, bc.Bary.y, bc.Bary.z))
		return false;

	bc.Fid = (int)fid;
	bc.Subface = (int)subface;

	return true;
}

lm::vec3f BaseMesh::GetPosFromBaryCoord(const BaryCoord& bc) const
{
	const BaseFace& f = m_Faces[bc.Fid];

	const lm::vec3f& v0 = m_Verts[f.m_VertIds[0]];
	const lm::vec3f& v1 = m_Verts[f.m_VertIds[1 + bc.Subface]];
	const lm::vec3f& v2 = m_Verts[f.m_VertIds[2 + bc.Subface]];

	return v0 * bc.Bary.x + v1 * bc.Bary.y + v2 * bc.Bary.z;
}


}
