#include "stdafx.h"
#include "GeomObject.h"

#include <C2/graph/MaterialSamples.h>

using namespace std;



namespace geom
{


GeomObject::GeomObject(void)
{
	m_Visible        = true;
	m_VertexOnlyMode = false;

	m_ObjectIndex = -1;

	m_FileFormat = GeomFileFormat::None;
}

void GeomObject::ClearObject(void)
{
	for (MeshBuf& mbuf : m_MeshAry)
	{
		mbuf.ClearAllBuf();
	}

	m_TextureLib.Clear();

	m_GTree.Clear();
}

const lm::range3f GeomObject::GetGeomBBox(bool for_ini) const
{
	lm::range3f r;
	for (const MeshBuf& m : m_MeshAry)
	{
		r.expand(for_ini ? m.GetBBoxIni() : m.GetBBox());
	}

	return r;
}

void GeomObject::InitializeBufferCommon(void)
{
	for (MeshBuf& mbuf : m_MeshAry)
	{
		mbuf.InitializeBuffer();

		// 面がなければ頂点モードを標準にする
		if (mbuf.m_Mesh.m_Faces.empty() && mbuf.m_Mesh.m_Polylines.empty())
			m_VertexOnlyMode = true;
	}
}


//! 形状に1対1で対応するファイルがある場合にtrueを返す.
bool GeomObject::IsFileObject(void) const
{
	if (m_FilePath.empty())
		return false;

	if (m_FileFormat == GeomFileFormat::None)
		return false;

	return true;
}


MeshBuf* GeomObject::CreateNewMeshBuf(void)
{
	MeshBuf* m = new MeshBuf(this);
	m->m_MBufIdx = (int)m_MeshAry.size();
	m_MeshAry.push_back(m);
	return m;
}


size_t GeomObject::GetNumTotalVerts(void) const
{
	size_t num = 0;
	for (const MeshBuf& mbuf : m_MeshAry)
	{
		num += mbuf.GetNumVerts();
	}
	return num;
}

size_t GeomObject::GetNumTotalFaces(void) const
{
	size_t num = 0;
	for (const MeshBuf& mbuf : m_MeshAry)
	{
		num += mbuf.GetNumFaces();
	}
	return num;
}

bool GeomObject::IsInChild(const MeshBuf* mbuf) const
{
	for (const MeshBuf& m : m_MeshAry)
	{
		if (&m == mbuf)
			return true;
	}

	return false;
}


void GeomObject::SetFrameShape(int frame)
{
	int a_frame = frame - 1;

	for (MeshBuf& m : m_MeshAry)
	{
		if (m.m_Bones.m_SrcVertPos.empty())
			continue;

		m.m_Mesh.m_Verts = m.m_Bones.m_SrcVertPos;
	}

	if (m_GTree.HasRoot())
	{
		SceneNode& n = m_GTree.GetRoot();
		ApplyTrans(n, n.GetFrameTransform(a_frame), a_frame);
	}
	
	for (MeshBuf& m : m_MeshAry)
	{
		std::vector<SkinWeight> VWeights;
		m.CalcSkinedPos(VWeights);
		m.UpdateToSkinedPos(VWeights);
	}
}

void GeomObject::ApplyTrans(SceneNode& n, const lm::matrix4f& trans, int a_frame)
{
	n.m_WorldTrans = trans;

	for (int mid : n.m_MeshIDs)
	{
		MeshBuf& mb = m_MeshAry[mid];
		if (!mb.m_Bones.m_Bones.empty())
			continue;

		mb.m_Mesh.ApplyTransform(trans);
	}

	for (SceneNode& cn : n.m_Children)
	{
		ApplyTrans(cn, cn.GetFrameTransform(a_frame) * trans, a_frame);
	}
}

void GeomObject::ResetSmoothNormal(void)
{
	for (MeshBuf& m : m_MeshAry)
	{
		m.m_Mesh.CreateNormalsEachVerts(true);
	}
}

bool GeomObject::HasMeshes(void) const
{
	return !m_MeshAry.empty();
}

void GeomObject::InitAllBBox(void)
{
	for (MeshBuf& mb : m_MeshAry)
	{
		mb.InitializeBBox();
	}
}

void GeomObject::UpdateBoneToNodeLink(SceneNode* sn)
{
	for (size_t k = 0; k < m_MeshAry.size(); ++k)
	{
		BoneDeform& bones = m_MeshAry[k].m_Bones;

		Bone* b = bones.FindBone(sn->m_Name);
		if (b == NULL)
			continue;

		sn->m_MeshIDs.push_back((int)k);
		sn->m_Bone = b;
	}
}


}
