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

#include <LibQtGeoViewerCore/GeomObject.h>



void VBOBuilder::CreateFromFaceGroup(GeometryVBO* vbo, lib_geo::BaseMesh& mesh, const geom::FaceGroup& fg)
{
	size_t triangles = 0;
	for(size_t i = 0; i < fg.m_Fids.size(); ++i)
	{
		triangles += mesh.m_Faces[fg.m_Fids[i]].NumTriangles();
	}

	lib_geo::BaseFace& tf = mesh.m_Faces[fg.GetTopFid()];

	vbo->NumTriangles = triangles;

	VBOBuilder builder;
	builder.ClearReserve(triangles, tf.HasNormal(), tf.HasUV());

	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;

			builder.verts.push_back(mesh.m_Verts[f.m_VertIds[i0]]);
			builder.verts.push_back(mesh.m_Verts[f.m_VertIds[i1]]);
			builder.verts.push_back(mesh.m_Verts[f.m_VertIds[i2]]);

			if(f.HasNormal())
			{
				builder.norms.push_back(mesh.m_Normals[f.m_NormIds[i0]]);
				builder.norms.push_back(mesh.m_Normals[f.m_NormIds[i1]]);
				builder.norms.push_back(mesh.m_Normals[f.m_NormIds[i2]]);
			}

			if(f.HasUV())
			{
				builder.uvs.push_back(mesh.m_UVs[f.m_UVIds[i0]]);
				builder.uvs.push_back(mesh.m_UVs[f.m_UVIds[i1]]);
				builder.uvs.push_back(mesh.m_UVs[f.m_UVIds[i2]]);
			}

			builder.IncrementIndex();
		}
	}

	builder.BuildVBO(vbo);
}

void VBOBuilder::ClearReserve(size_t num_triangles, bool enable_normal, bool enable_uv)
{
	verts.reserve(num_triangles * 3);
	indexbuf.reserve(num_triangles * 3);

	if(enable_normal)
		norms.reserve(num_triangles * 3);

	if(enable_uv)
		uvs.reserve(num_triangles * 3);
}

void VBOBuilder::BuildVBO(GeometryVBO* vbo)
{
	vbo->m_Vertex.GenerateBuffer();
	vbo->m_Vertex.BindArray();
	glBufferData(GL_ARRAY_BUFFER, verts.size() * 3*4, verts[0].v(), GL_STATIC_DRAW);

	if(!norms.empty())
	{
		vbo->m_Normal.GenerateBuffer();
		vbo->m_Normal.BindArray();
		glBufferData(GL_ARRAY_BUFFER, norms.size() * 3*4, norms[0].v(), GL_STATIC_DRAW);
	}

	if(!uvs.empty())
	{
		vbo->m_Texture.GenerateBuffer();
		vbo->m_Texture.BindArray();
		glBufferData(GL_ARRAY_BUFFER, uvs.size() * 2*4, uvs[0].v(), GL_STATIC_DRAW);
	}

	vbo->m_Index.GenerateBuffer();
	vbo->m_Index.BindElementArray();
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexbuf.size()*4, &indexbuf[0], GL_STATIC_DRAW);
}

void VBOBuilder::IncrementIndex(void)
{
	indexbuf.push_back(indexbuf.size());
	indexbuf.push_back(indexbuf.size());
	indexbuf.push_back(indexbuf.size());
}
