///////////////////////////////////////////////////////////////////////////////
/// @file deMeshOpt.cpp
///
/// @brief Mesh optimizer class
///
/// @author Assassin 
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Feb 2003
/// @author Assassin
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#pragma warning (push,3) // STL makes a LOT of warnings on level 4
#pragma warning (disable : 4786) // truncating class name in debug info
#include "TriStripper/tri_stripper.h"
#pragma warning (pop)

#include "deMeshOpt.hpp"
#include "deDriver.hpp"

class deMeshOptimizer : public IdeMeshOptimizer
{
public:
	deMeshOptimizer();
	~deMeshOptimizer();
	
	deBoolean OptimizeIndices(IdeVertexBuffer * VBuffer, long VCacheSize, deBoolean CCW);
	deBoolean ReorderAllData(IdeVertexBuffer * VBuffer, long VCacheSize, deBoolean CCW);
};

static deMeshOptimizer s_TheOptimizer;
IdeMeshOptimizer* IdeMeshOptimizer_GetMeshOptPtr()
{
	return &s_TheOptimizer;
}

deMeshOptimizer::deMeshOptimizer()
{
}

deMeshOptimizer::~deMeshOptimizer()
{
}

deBoolean deMeshOptimizer::OptimizeIndices(IdeVertexBuffer * VBuffer, long VCacheSize, deBoolean CCW)
{
	if (VBuffer == NULL)
	{
		DEBUGRETURN(deFALSE, "OptimizeIndices: Specified argument was NULL: VBuffer");
	}

	long Size;
	unsigned short * IndexBuffer;
	VBuffer->Lock();

	{
		IndexBuffer = (unsigned short *)VBuffer->GetBuffer(IdeVertexBuffer::BUFFER_INDICES16);
		Size = VBuffer->GetIndexCount();
		if (!IndexBuffer)
		{
			VBuffer->Unlock();
			DEBUGRETURN(deFALSE, "OptimizeIndices: VBuffer does not have a 16-bit index stream");
		}
	}
	std::vector <unsigned short> Indices(IndexBuffer, IndexBuffer + Size);

	// create the triangle-stripping object
	triangle_stripper::tri_stripper stripper(Indices);
	triangle_stripper::tri_stripper::primitives_vector prims;

	// set the cache size
	stripper.SetCacheSize(VCacheSize);
	stripper.SetMinStripSize(2);

	stripper.Strip(&prims);

	{
		unsigned int i, j, k;
		k = 0;
		for (i = 0; i < prims.size(); ++i)
		{
			if (prims[i].m_Type == triangle_stripper::tri_stripper::PT_Triangle_Strip)
			{
				for (j = 2; j < prims[i].m_Indices.size(); ++j)
				{
					// have to swap vertex winding each one
					if (deXOR(j%2,CCW))
					{
						IndexBuffer[k*3+0] = prims[i].m_Indices[j-2];
						IndexBuffer[k*3+1] = prims[i].m_Indices[j-1];
						IndexBuffer[k*3+2] = prims[i].m_Indices[j-0];
					}
					else
					{
						IndexBuffer[k*3+2] = prims[i].m_Indices[j-2];
						IndexBuffer[k*3+1] = prims[i].m_Indices[j-1];
						IndexBuffer[k*3+0] = prims[i].m_Indices[j-0];
					}
					++k;
				}
			}
			else
			{
				for (j = 0; j < prims[i].m_Indices.size(); j += 3)
				{
					if (CCW)
					{
						IndexBuffer[k*3+0] = prims[i].m_Indices[j+0];
						IndexBuffer[k*3+1] = prims[i].m_Indices[j+1];
						IndexBuffer[k*3+2] = prims[i].m_Indices[j+2];
					}
					else
					{
						IndexBuffer[k*3+2] = prims[i].m_Indices[j+0];
						IndexBuffer[k*3+1] = prims[i].m_Indices[j+1];
						IndexBuffer[k*3+0] = prims[i].m_Indices[j+2];
					}
					++k;
				}
			}
		}
	}

	VBuffer->Unlock();

	return deTRUE;
}

deBoolean deMeshOptimizer::ReorderAllData(IdeVertexBuffer * VBuffer, long VCacheSize, deBoolean CCW)
{
#pragma todo (unfinished function: ReorderAllData)
	if (!OptimizeIndices(VBuffer, VCacheSize, CCW))
		return deFALSE;
	return deFALSE;
}

