#include "stdafx.h"
#include "VBOBuilder.h"

#include <LibQtGeoViewerCore/GeomObject.h>



void GeomVBOTriCache::Create(lib_geo::BaseMesh& mesh, const geom::FaceGroup& fg)
{
	lib_geo::BaseFace& tf = mesh.m_Faces[fg.GetTopFid()];

	num_triangles = GetNumTrianglesFG(mesh, fg);

	ClearReserve(num_triangles, tf.HasNormal(), tf.HasUV(), mesh.HasTangent(), mesh.HasVCol());

	for (size_t i = 0; i < fg.m_Fids.size(); ++i)
	{
		lib_geo::BaseFace& f = mesh.m_Faces[fg.m_Fids[i]];
		for (size_t j = 0; j < f.NumTriangles(); ++j)
		{
			int i0 = 0;
			int i1 = j + 1;
			int i2 = j + 2;

			CopyFV(mesh, f, i0, i1, i2);

			if (f.HasNormal())
				CopyFN(mesh, f, i0, i1, i2);

			if (f.HasUV())
				CopyFUV(mesh, f, i0, i1, i2);

			if (mesh.HasVCol())
				CopyFVCol(mesh, f, i0, i1, i2);

			if (mesh.HasTangent())
				CopyFT(mesh, f, i0, i1, i2);

			IncrementTriangleIndex();
		}
	}
}

void GeomVBOTriCache::CopyFV(lib_geo::BaseMesh& mesh, lib_geo::BaseFace& f, int i0, int i1, int i2)
{
	int vi0 = f.m_VertIds[i0];
	int vi1 = f.m_VertIds[i1];
	int vi2 = f.m_VertIds[i2];
	verts.push_back(mesh.m_Verts[vi0]);
	verts.push_back(mesh.m_Verts[vi1]);
	verts.push_back(mesh.m_Verts[vi2]);
}

void GeomVBOTriCache::CopyFN(lib_geo::BaseMesh& mesh, lib_geo::BaseFace& f, int i0, int i1, int i2)
{
	int ni0 = f.m_NormIds[i0];
	int ni1 = f.m_NormIds[i1];
	int ni2 = f.m_NormIds[i2];
	norms.push_back(mesh.m_Normals[ni0]);
	norms.push_back(mesh.m_Normals[ni1]);
	norms.push_back(mesh.m_Normals[ni2]);
}

void GeomVBOTriCache::CopyFUV(lib_geo::BaseMesh& mesh, lib_geo::BaseFace& f, int i0, int i1, int i2)
{
	int ti0 = f.m_UVIds[i0];
	int ti1 = f.m_UVIds[i1];
	int ti2 = f.m_UVIds[i2];
	uvs.push_back(mesh.m_UVs[ti0]);
	uvs.push_back(mesh.m_UVs[ti1]);
	uvs.push_back(mesh.m_UVs[ti2]);
}

void GeomVBOTriCache::CopyFT(lib_geo::BaseMesh& mesh, lib_geo::BaseFace& f, int i0, int i1, int i2)
{
	int ti0 = f.m_UVIds[i0];
	int ti1 = f.m_UVIds[i1];
	int ti2 = f.m_UVIds[i2];
	tangents.push_back(mesh.m_Tangents[ti0]);
	tangents.push_back(mesh.m_Tangents[ti1]);
	tangents.push_back(mesh.m_Tangents[ti2]);
}

void GeomVBOTriCache::CopyFVCol(lib_geo::BaseMesh& mesh, lib_geo::BaseFace& f, int i0, int i1, int i2)
{
	int vi0 = f.m_VertIds[i0];
	int vi1 = f.m_VertIds[i1];
	int vi2 = f.m_VertIds[i2];
	vcol.push_back(mesh.m_Col[vi0]);
	vcol.push_back(mesh.m_Col[vi1]);
	vcol.push_back(mesh.m_Col[vi2]);
}

size_t GeomVBOTriCache::GetNumTrianglesFG(lib_geo::BaseMesh& mesh, const geom::FaceGroup& fg) const
{
	size_t triangles = 0;
	for (size_t i = 0; i < fg.m_Fids.size(); ++i)
	{
		triangles += mesh.m_Faces[fg.m_Fids[i]].NumTriangles();
	}
	return triangles;
}

void GeomVBOTriCache::IncrementTriangleIndex(void)
{
	indexbuf.push_back(indexbuf.size());
	indexbuf.push_back(indexbuf.size());
	indexbuf.push_back(indexbuf.size());
}

void GeomVBOTriCache::ClearReserve(size_t num_triangles, bool enable_normal, bool enable_uv, bool enable_tangent, bool enable_vcol)
{
	size_t buf_len = num_triangles * 3;

	verts.reserve(buf_len);
	indexbuf.reserve(buf_len);

	if (enable_normal)
		norms.reserve(buf_len);

	if (enable_vcol)
		vcol.reserve(buf_len);

	if (enable_uv)
		uvs.reserve(buf_len);

	if (enable_tangent)
		tangents.reserve(buf_len);
}


void GeomVBOBuilder::CreateFromFaceGroup(GeometryVBO* vbo, lib_geo::BaseMesh& mesh, const geom::FaceGroup& fg)
{
	GeomVBOTriCache cache;
	cache.Create(mesh, fg);

	vbo->NumTriangles = cache.num_triangles;
	
	if (!cache.verts.empty())
		vbo->m_Vertex.AssginBuffer3f(cache.verts);

	if (!cache.vcol.empty())
		vbo->m_VCol.AssginBuffer3f(cache.vcol);

	if (!cache.norms.empty())
		vbo->m_Normal.AssginBuffer3f(cache.norms);

	if (!cache.uvs.empty())
		vbo->m_Texture.AssginBuffer2f(cache.uvs);

	if (!cache.tangents.empty())
		vbo->m_Tangents.AssginBuffer3f(cache.tangents);

	if (!cache.indexbuf.empty())
		vbo->m_Index.AssginBufferi(cache.indexbuf);
}
