#pragma once

#include "BaseMeshPrimitives.h"
#include "BaryCoord.h"

#include <C2/lm/matrix4.h>



namespace lib_geo
{


// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//! 基本メッシュ
class BaseMesh
{
public:
	virtual void Clear(void);

	virtual bool HasNormal  (void) const { return !m_Normals.empty();  }
	virtual bool HasUV      (void) const { return !m_UVs.empty();      }
	virtual bool HasEdge    (void) const { return !m_Edges.empty();    }
	virtual bool HasVertAdj (void) const { return !m_VertAdj.empty();  }
	virtual bool HasTangent (void) const { return !m_Tangents.empty(); }
	virtual bool HasVCol    (void) const { return !m_Col.empty();      }

	virtual void CreateNormalsEachVerts(bool resetSmooth);
	virtual void UpdateNormal(void);
	virtual void UpdateAdjVertNormal(void);

	virtual void CreateEdgeFromFace(void);

	virtual void CreateTangentsByUV(void);

	virtual void ClearAllAdjBuffer(void);
	virtual void CreateAdjBuffers(void);
	virtual void CreateUVsEachVerts(void);

	lm::range3f CalcAABB(void) const;

	//! 4頂点以上のポリゴンの三角化.
	virtual void Triangulate(void);

	//! 未使用頂点バッファを切り詰める.
	virtual void RemoveNotReferencedVertex(void);
	virtual void GetReferencedVertMap(std::vector<bool>& VertRef, std::vector<bool>& NormalRef, std::vector<bool>& UVRef) const;

	//! 隣接頂点の結合
	virtual void RemDoubleVertex(void);

	virtual void Translate( const lm::vec3f& v );
	virtual void Translate( float x , float y , float z );
	virtual void Scale( float s );
	virtual void Scale( float sx , float sy , float sz );

	virtual void RotateX( float angle );
	virtual void RotateY( float angle );
	virtual void RotateZ( float angle );
	virtual void Rotate( const lm::vec3f& axis , float angle );

	//! 三角化したときの三角形の枚数を取得する.
	size_t NumTriangles(void) const;

	//! 頂点単位の平均法線を取得する
	virtual void CalcNormalEachVerts(std::vector<lm::vec3f>& normals) const;

	//! 指定面の中心位置(頂点の平均)を取得する
	lm::vec3f GetFaceCenter(const size_t face_idx) const;
	lm::vec3f GetFaceCenter(const BaseFace& f) const;
	lm::vec3f GetFaceNormal(const BaseFace& f) const;
	lm::vec3f CalcFaceNormal(const BaseFace& f, int lvid0, int lvid1, int lvid2) const;

	virtual void MergeLinkedPolylines(void);

	bool GetClosestSubfacePos(const lm::vec3f& pos, SubfaceIdx& sf, lm::vec3f& close_pos) const;

	bool CalcBaryCoord(const lm::vec3f& pos, size_t fid, size_t subface, float& u, float& v, float& w) const;
	bool CalcBaryCoord(const lm::vec3f& pos, size_t fid, size_t subface, lm::vec3f& bc) const;
	bool CalcBaryCoord(const lm::vec3f& pos, size_t fid, size_t subface, BaryCoord& bc) const;

	lm::vec3f GetPosFromBaryCoord(const BaryCoord& bc) const;

	void CopySwap(BaseMesh& m);

	void ApplyTransform(const lm::matrix4f& m);

	void SyncFaceVidToNid(void);
	void SyncFaceVidToUVid(void);

private:
	bool CalcBaryCoordMain(const lm::vec3f& pos, size_t fid, size_t subface, float& u, float& v, float& w) const;

	void ResetNormalToZero(void);
	void NormalizeNormal(void);

	void SetAdj_VtoF(void);
	void SetAdj_VtoE(void);
	void SetAdj_EtoF(void);

public:
	std::vector< lm::vec3f >  m_Verts;
	std::vector< lm::vec3f >  m_Normals;
	std::vector< lm::vec2f >  m_UVs;
	std::vector< lm::vec3f >  m_Tangents;
	std::vector<lgr::color3f> m_Col;

	std::vector< VertAdj  >     m_VertAdj;
	std::vector< BaseFace >     m_Faces;
	std::vector< BaseEdge >     m_Edges;
	std::vector< BasePolyline > m_Polylines;

	std::vector<BaseMaterial>  m_Materials;
};


}
