/*********************************************************************NVMH2****
Copyright (C) 1999, 2000, 2001 NVIDIA Corporation
This file is provided without support, instruction, or implied warranty of any
kind.  NVIDIA makes no guarantee of its fitness for a particular purpose and is
not liable under any circumstances for any damages or loss whatsoever arising
from the use or inability to use this file or items derived from it.

Comments: 
	A utility class that takes data generated by a nvMeshIO implementation such as
	nvObjIO and handles things like smoothing groups. 

    Usage: 
		1. First set all the attributes you would like to process using 
		SetAttributeData(...) iteratively over all the attributes. In particular, 
		you must set nvMeshIO::ATTRIBUTE_NAMES[nvMeshIO::VERTEX_POSITION]. 
		
		2. Call SetGroupInfo(...) for all the groups for each attribute.

		3. Call GetNewNumElements(attribute) for all the attributes you passed in first
		step. 
		
		4. Allocate new arrays of size GetNewNumElements(attributes)*size(attribute)

		5. Call GetNewAttributeArray(attribute,newArray) for each new attribute array.
		  

******************************************************************************/

#ifndef __NV_MESH_PREPROCESSOR_H
#define __NV_MESH_PREPROCESSOR_H

#ifdef _WIN32
#  pragma warning (disable : 4786)
#endif
#include <vector>

#ifdef _WIN32
#  pragma warning (disable : 4786)
#endif
#include <map>

#ifdef _WIN32
#  pragma warning (disable : 4786)
#endif
#include <string>

#ifdef _WIN32
#pragma warning (disable : 4786)
#endif
#include <set>

#include "nvMeshIO.h"

struct nvPreprocessorGroup
{
	nvPreprocessorGroup() {
		m_numTriangles = 0;
	}
	std::string m_name; 
	unsigned int m_numTriangles;
	std::vector<int> m_triangleIndices; // Triangles in this group.
	std::vector<int> m_dataIndices; // Indices into the data associated with this group. E.g., if this
		// group is a smoothing group, dataIndices will index into the normals array if it exists. Size of 
		// dataIndices should be same as size of triangle indices.
	std::vector<int> m_indexedTriangles;
};

class nvMeshPreprocessor
{
public:

	~nvMeshPreprocessor();
	nvMeshPreprocessor();
	// Returns 1 if attribute is one that it understands. Else returns 0. Use this to set
	// the various data that you have extracted, for example, by invoking nvMeshIO.
	int SetAttributeData(const char* attribute, const void* data, const size_t& attributeSize, 
		const size_t& numElements);
	
	int SetGroupInfo(const char* attribute, const char* groupName, 
		const std::vector<int>& groupTriangleIndices, const std::vector<int>& groupAttributeIndices,
		const std::vector<int>& indexedTriangles);

	void SetTriInfo(const std::vector<nvTriInfo>& triInfo);

	size_t GetNewNumTriangles();
	void GetNewTriangleIndices(std::vector<int>& triangleIndices);
	size_t GetNewNumElements(const char* attribute);

	// newArray must be allocated by caller to size = GetNewNumElements(attribute)*Size(attribute), where
	// size(attribute) is known to caller (e.g. from nvMeshIO).
	int GetNewAttributeArray(const char* attribute, std::vector<float>& values);

private:
	void PreprocessTriangles();
	void ProcessSmoothingGroups();
	void UpdateNormals(int j, int newIndex, nvTriInfo* triInfo);
	void UpdateTexCoords0(int j, int newIndex, nvTriInfo* triInfo);
	
	void CheckTexCoords();
private:
	bool m_done;

	size_t m_numVertices;
	float* m_vertexPositions;
	size_t m_numNormals;
	float* m_vertexNormals;
	size_t m_numTexCoords;
	float* m_texCoords;
	size_t m_texCoordSize;
	
	size_t m_numTriangles;
	int* m_triangleIndices;

	std::vector<nvTriInfo> m_triInfo;
	std::map<int, std::vector<nvTriInfo> > m_triInfoMap;
	std::map<int, std::set<int> > m_vertexToGeometryGroupMap;
	std::map<int, std::set<int> > m_vertexToSmoothingGroupMap;
	std::map<int, std::set<int> > m_vertexToTexCoordGroupMap;
	
	std::map<int, int> m_newVertexIndexToOldMap;
	std::map<int, int> m_newVertexIndexToTriangleIndexMap;

	
	size_t m_newNumVertices;
	std::vector<float> m_newVertexPositions;
	std::vector<float> m_newVertexNormals;
	std::vector<bool> m_normalDefined;
	std::vector<int> m_newTriangleIndices;
	std::vector<float> m_newTexCoords;
	std::vector<bool> m_texcoordDefined;
	bool m_allNormalsDefined;
	bool m_allTexcoordsDefined;

	// Local data structure for float triple.
	typedef struct
	{
		float data[3];
	} TriFloat;

	std::map<int, TriFloat> m_newVertexIndexToNormalMap;
	std::map<int, TriFloat> m_newVertexIndexToTexCoord0Map;

	typedef std::map<std::string, nvPreprocessorGroup*> tnameToSmoothingGroupMap;
	tnameToSmoothingGroupMap m_nameToSmoothingGroupMap;
	std::map<std::string, nvPreprocessorGroup*> m_nameToTexCoordGroupMap;
	
};


#endif
