#include "ObjectRenderer.h"
#include "Model.h"
#include "VisibleObject.h"
#include <Math/Vector.h>
#include <Utility/Log.h>

#include <vector>

//////////////////////////////////////////////////////////////
namespace Dubious {
namespace Renderer {

namespace
{
struct BufferData
{
	BufferData( const Math::LocalVector& V, const Math::LocalVector& N )
	{
		x = V.X();
		y = V.Y();
		z = V.Z();
		nx = N.X();
		ny = N.Y();
		nz = N.Z();
	}
	float x, y, z;
	float nx, ny, nz;
private:
	BufferData();
};
typedef std::vector<BufferData> BufferDataVect;
typedef std::vector<unsigned short> IndicesVect;

//////////////////////////////////////////////////////////////
void FillBufferDataVect( ModelPtr pModel, BufferDataVect& Data )
{
	const LocalVectorVector& Points( pModel->Points() );
	const Model::SurfaceVector& Surfaces( pModel->Surfaces() );
	const Math::LocalVector& Offset( pModel->Offset() );

	for( size_t i=0; i<Surfaces.size(); ++i ){
		const Math::LocalVector& A( Points[Surfaces[i].p0] );
		const Math::LocalVector& B( Points[Surfaces[i].p1] );
		const Math::LocalVector& C( Points[Surfaces[i].p2] );
		const Math::LocalVector& Normal = Surfaces[i].Normal;

		Data.push_back( BufferData(A + Offset, Normal) );
		Data.push_back( BufferData(B + Offset, Normal) );
		Data.push_back( BufferData(C + Offset, Normal) );
	}
	const ModelPtrVector& Kids = pModel->Kids();
	for( size_t i=0; i<Kids.size(); ++i ) {
		FillBufferDataVect( Kids[i], Data );
	}
}
}
int ObjectRenderer::VBOData::SIZEOF_BUFFER_DATA = sizeof(BufferData);

//////////////////////////////////////////////////////////////
ObjectRenderer::VBOData ObjectRenderer::BindToVBO( VisibleObjectPtr pObject )
{
	BufferDataVect Data;
	FillBufferDataVect( pObject->Model(), Data );

	IndicesVect Indices;
	for (unsigned short i=0; i<Data.size(); ++i) {
		Indices.push_back( i );
	}

	VBOData VBOBuffer;

	glGenBuffers(1, &VBOBuffer.VertexID);
	glBindBuffer(GL_ARRAY_BUFFER, VBOBuffer.VertexID);
	glBufferData(GL_ARRAY_BUFFER, VBOData::SIZEOF_BUFFER_DATA*Data.size(), &(Data[0]), GL_STATIC_DRAW);

	glGenBuffers(1, &VBOBuffer.IndexID);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBOBuffer.IndexID);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*Indices.size(), &(Indices[0]), GL_STATIC_DRAW);

	VBOBuffer.IndexCount = Indices.size();

	return VBOBuffer;
}

}
}
