#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)
{
	m_Mesh.Clear();

	ClearTexture();

	ClearSelect();

	m_FaceMatGroup.clear();

	m_VertLinkers.clear();

	m_BoneAnimation.Clear();
}


void GeomObject::InitializeBufferCommon(void)
{
	lib_geo::BaseMesh& base_mesh = m_Mesh;

	// create uv
	if (!base_mesh.HasUV())
	{
		base_mesh.CreateUVsEachVerts();
	}

	if (base_mesh.m_Materials.empty())
	{
		base_mesh.m_Materials.push_back(lib_graph::MaterialSamples::GetSilver());
		for (size_t i = 0; i < base_mesh.m_Faces.size(); ++i)
		{
			base_mesh.m_Faces[i].m_MatIdx = 0;
		}

		CreateTextureBuf(1);
	}

	UpdateBBox();

	CreateFaceMatGroup();

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

void GeomObject::CreateAdjBufOnce(void)
{
	if(m_Mesh.HasVertAdj())
		return;

	m_Mesh.CreateAdjBuffers();
}


void GeomObject::UpdateBBox(void)
{
	m_BBox = m_Mesh.CalcAABB();
}


void GeomObject::FlipFace(void)
{
	for (lib_geo::BaseFace& f : m_Mesh.m_Faces)
	{
		std::reverse(f.m_VertIds.begin(), f.m_VertIds.end());
		std::reverse(f.m_NormIds.begin(), f.m_NormIds.end());
		std::reverse(f.m_UVIds.begin(), f.m_UVIds.end());
		std::reverse(f.m_AdjEids.begin(), f.m_AdjEids.end());
	}

	for (lm::vec3f& n : m_Mesh.m_Normals)
	{
		n *= -1.0f;
	}

	for (lib_geo::VertAdj& a : m_Mesh.m_VertAdj)
	{
		std::reverse(a.m_AdjEids.begin(), a.m_AdjEids.end());
		std::reverse(a.m_AdjFids.begin(), a.m_AdjFids.end());
		a.m_NormalAvg *= -1.0f;
	}
}


void GeomObject::ClearSelect(void)
{
	m_SelVerts.clear();
}

void GeomObject::SwapVertSelect(int vidx)
{
	map<int, bool>::iterator i = m_SelVerts.find(vidx);
	if(i == m_SelVerts.end())
		m_SelVerts[vidx] = true;
	else
		m_SelVerts.erase(i);
}

void GeomObject::SetVertSelect(int vidx, bool select)
{
	map<int, bool>::iterator i = m_SelVerts.find(vidx);
	if(select)
	{
		if(i == m_SelVerts.end())
			m_SelVerts[vidx] = true;
	}
	else
	{
		if(i != m_SelVerts.end())
			m_SelVerts.erase(i);
	}
}

bool GeomObject::GetVertSelect(int vidx) const
{
	map<int, bool>::const_iterator i = m_SelVerts.find(vidx);
	if(i == m_SelVerts.end())
		return false;

	return i->second;
}


void GeomObject::CreateFaceMatGroup(void)
{
	m_FaceMatGroup.clear();

	for(size_t i = 0; i < m_Mesh.m_Faces.size(); ++i)
	{
		int mat_idx = m_Mesh.m_Faces[i].m_MatIdx;

		FaceGroup& mg = m_FaceMatGroup[mat_idx];
		mg.m_GroupID = mat_idx;
		mg.m_Fids.push_back((int)i);
	}
}


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

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

	return true;
}


void GeomObject::UpdateCrossSection(bool SplitGroup, const lib_geo::Plane& cutplane)
{
	lib_geo::BaseMesh& m = m_Mesh;

	if (!m.HasEdge())
	{
		m.CreateEdgeFromFace();
		m.CreateAdjBuffers();
	}

	if (SplitGroup)
		m_CrossSection.CreateCrossSectionEachGroup(m, cutplane);
	else
		m_CrossSection.CreateCrossSectionWhole(m, cutplane);
}


void GeomObject::Triangulate(void)
{
	lib_geo::BaseMesh& m = m_Mesh;

	m.Triangulate();

	CreateFaceMatGroup();
}


void GeomObject::ClearTexture(void)
{
	for (GeomTextureSet& t : m_Textures)
	{
		t.ReleaseAll();
	}
	m_Textures.clear();

	for (gl::GlTexture& t : m_ColorTextureBuf)
	{
		t.FinalizeTexture();
	}
	m_ColorTextureBuf.clear();
}

bool GeomObject::IsValidMaterialIdx(int idx) const
{
	return !(idx < 0 || (int)m_Mesh.m_Materials.size() <= idx);
}


void GeomObject::InitColorTexture(int idx, const std::string& filepath, const std::string& name, const gl::TextureConfig& config)
{
	GeomTextureSet& tex_set = m_Textures[idx];

	for (gl::GlTexture& tex : m_ColorTextureBuf)
	{
		if (tex.GetSourceFilePath() == filepath)
		{
			tex_set.TexColor = &tex;
			return;
		}
	}

	gl::GlTexture* ctex = new gl::GlTexture;
	m_ColorTextureBuf.push_back(ctex);

	ctex->SetName(name);

	if (!ctex->LoadTextureFromFile(filepath.c_str(), false))
	{
		m_ColorTextureBuf.pop_back();
		return;
	}

	ctex->InitializeTexture();
	ctex->SetTextureGLAndReleaseImage(config);

	tex_set.TexColor = ctex;
}

GeomTextureSet* GeomObject::GetTextureFromFace(const lib_geo::BaseFace& f)
{
	return GetTexture(f.m_MatIdx);
}

GeomTextureSet* GeomObject::GetTexture(const int idx)
{
	if (m_Textures.empty())
		return NULL;

	if (!IsValidMaterialIdx(idx))
		return NULL;

	return &m_Textures[idx];
}

void GeomObject::CreateTextureBuf(size_t size)
{
	m_Textures.resize(size);
}


}
