/*!********************************************************************************************
 @Function		generate_border
 @Input			anchor_index      The anchor index to center the quad around.
 @Input			left_offset       The width of the quad left from the anchor.
 @Input			right_offset      The width of the quad right from the anchor.
 @Input			pivot             The pivot used for all vertices.
 @Input			texmat            The texture atlas used for uv-coordinate calculation.
 @Output		pivotquads        The generated pivotquad vertex data.
 @Output		triangle          Triangle indices used for rendering of the pivotquads. 
 @Description	Generates a single quad which can be used e.g. to render a rectangle behind text.
***********************************************************************************************/
void generate_border(const int anchor_index, const int left_offset, const int right_offset, const PVRTVec2 &pivot, PVRTMat3 &texmat, PVRTPivotQuadVertexVector &pivotquads, PVRTTriangleVector &triangles)
{
	unsigned int triangle_index = pivotquads.size();

	PVRTVec3 uvcoords;		
	PVRTPivotQuadVertex vertex;
	vertex.origin = pivot;

	// Left cap
	uvcoords = texmat * PVRTVec3(0.0f, 0.0f, 1.0f);
	vertex.word_index =  -anchor_index - left_offset;
	vertex.height_index = 0;
	vertex.u = (PVRTuint8)(uvcoords.x * 255.0f);
	vertex.v = (PVRTuint8)(uvcoords.y * 255.0f);
	pivotquads.push_back(vertex);

	uvcoords = texmat * PVRTVec3(0.5f, 0.0f, 1.0f);
	vertex.word_index = -anchor_index - left_offset + 1;
	vertex.height_index = 0;
	vertex.u = (PVRTuint8)(uvcoords.x * 255.0f);
	vertex.v = (PVRTuint8)(uvcoords.y * 255.0f);
	pivotquads.push_back(vertex);

	uvcoords = texmat * PVRTVec3(0.0f, 1.0f, 1.0f);
	vertex.word_index = -anchor_index - left_offset;
	vertex.height_index = 1;
	vertex.u = (PVRTuint8)(uvcoords.x * 255.0f);
	vertex.v = (PVRTuint8)(uvcoords.y * 255.0f);
	pivotquads.push_back(vertex);

	uvcoords = texmat * PVRTVec3(0.5f, 1.0f, 1.0f);
	vertex.word_index = -anchor_index - left_offset + 1;
	vertex.height_index = 1;
	vertex.u = (PVRTuint8)(uvcoords.x * 255.0f);
	vertex.v = (PVRTuint8)(uvcoords.y * 255.0f);
	pivotquads.push_back(vertex);

	PVRTTriangle t0 = { triangle_index, triangle_index + 1, triangle_index + 3 };
	PVRTTriangle t1 = { triangle_index, triangle_index + 3, triangle_index + 2 };

	triangles.push_back(t0);
	triangles.push_back(t1);
	triangle_index = pivotquads.size();

	// Middle part
	uvcoords = texmat * PVRTVec3(0.5f, 0.0f, 1.0f);
	vertex.word_index =  -anchor_index - left_offset + 1;
	vertex.height_index = 0;
	vertex.u = (PVRTuint8)(uvcoords.x * 255.0f);
	vertex.v = (PVRTuint8)(uvcoords.y * 255.0f);
	pivotquads.push_back(vertex);

	uvcoords = texmat * PVRTVec3(0.5f, 0.0f, 1.0f);
	vertex.word_index = anchor_index + right_offset - 1;
	vertex.height_index = 0;
	vertex.u = (PVRTuint8)(uvcoords.x * 255.0f);
	vertex.v = (PVRTuint8)(uvcoords.y * 255.0f);
	pivotquads.push_back(vertex);

	uvcoords = texmat * PVRTVec3(0.5f, 1.0f, 1.0f);
	vertex.word_index = -anchor_index - left_offset + 1;
	vertex.height_index = 1;
	vertex.u = (PVRTuint8)(uvcoords.x * 255.0f);
	vertex.v = (PVRTuint8)(uvcoords.y * 255.0f);
	pivotquads.push_back(vertex);

	uvcoords = texmat * PVRTVec3(0.5f, 1.0f, 1.0f);
	vertex.word_index = anchor_index + right_offset - 1;
	vertex.height_index = 1;
	vertex.u = (PVRTuint8)(uvcoords.x * 255.0f);
	vertex.v = (PVRTuint8)(uvcoords.y * 255.0f);
	pivotquads.push_back(vertex);

	PVRTTriangle t2 = { triangle_index, triangle_index + 1, triangle_index + 3 };
	PVRTTriangle t3 = { triangle_index, triangle_index + 3, triangle_index + 2 };

	triangles.push_back(t2);
	triangles.push_back(t3);
	triangle_index = pivotquads.size();

	// Right cap
	uvcoords = texmat * PVRTVec3(0.5f, 0.0f, 1.0f);
	vertex.word_index =  anchor_index + right_offset - 1;
	vertex.height_index = 0;
	vertex.u = (PVRTuint8)(uvcoords.x * 255.0f);
	vertex.v = (PVRTuint8)(uvcoords.y * 255.0f);
	pivotquads.push_back(vertex);

	uvcoords = texmat * PVRTVec3(1.0f, 0.0f, 1.0f);
	vertex.word_index = anchor_index + right_offset;
	vertex.height_index = 0;
	vertex.u = (PVRTuint8)(uvcoords.x * 255.0f);
	vertex.v = (PVRTuint8)(uvcoords.y * 255.0f);
	pivotquads.push_back(vertex);

	uvcoords = texmat * PVRTVec3(0.5f, 1.0f, 1.0f);
	vertex.word_index = anchor_index + right_offset - 1;
	vertex.height_index = 1;
	vertex.u = (PVRTuint8)(uvcoords.x * 255.0f);
	vertex.v = (PVRTuint8)(uvcoords.y * 255.0f);
	pivotquads.push_back(vertex);

	uvcoords = texmat * PVRTVec3(1.0f, 1.0f, 1.0f);
	vertex.word_index = anchor_index + right_offset;
	vertex.height_index = 1;
	vertex.u = (PVRTuint8)(uvcoords.x * 255.0f);
	vertex.v = (PVRTuint8)(uvcoords.y * 255.0f);
	pivotquads.push_back(vertex);

	PVRTTriangle t4 = { triangle_index, triangle_index + 1, triangle_index + 3 };
	PVRTTriangle t5 = { triangle_index, triangle_index + 3, triangle_index + 2 };

	triangles.push_back(t4);
	triangles.push_back(t5);
}
/*!********************************************************************************************
 @Function		convert_signs
 @Input			layer          The map layer to extract the texts from.
 @Input			atlas          The texture atlas used for uv-coordinate calculation.
 @Output		pivotquads     The generated pivotquad vertex data.
 @Output		triangles      Triangle indices used for rendering of the pivotquads. 
 @Description	Generates pivotquads for the signs which will be screen-space aligned when being 
                rendered.
***********************************************************************************************/
void convert_signs(const PVRTMapLayer &layer, const PVRTTextureAtlas &atlas, PVRTPivotQuadVertexVector &pivotquads, PVRTTriangleVector &triangles)
{
	unsigned int numTotalSigns = layer.indexset.signs.size();
	
	// Pre-allocate to prevent reallocations
	pivotquads.reserve(pivotquads.size() + numTotalSigns * 4);
	triangles.reserve(triangles.size() + numTotalSigns * 2);
	
	for (unsigned int j=0; j < numTotalSigns; j++)
	{	
		const unsigned int index = pivotquads.size();

		string name(layer.indexset.signs[j].szName);
		
		PVRTVec2 pos = layer.indexset.signs[j].position;

		if (!atlas.Contains(name))
		{
			cerr << "Error: Texture atlas does not contain " << name << endl;
			continue;
		}

		PVRTMat3 texmat = atlas.GetTextureMatrix(name);
		PVRTVec3 uvcoords;

		PVRTPivotQuadVertex vertex;
		vertex.origin = pos;
		

		uvcoords = texmat * PVRTVec3(0.0f, 0.0f, 255.0f);
		vertex.word_index = 0;
		vertex.height_index = 0;
		vertex.u = (PVRTuint8)(uvcoords.x);
		vertex.v = (PVRTuint8)(uvcoords.y);
		pivotquads.push_back(vertex);

		uvcoords = texmat * PVRTVec3(255.0f, 0.0f, 255.0f);
		vertex.word_index = 1;
		vertex.height_index = 0;
		vertex.u = (PVRTuint8)(uvcoords.x);
		vertex.v = (PVRTuint8)(uvcoords.y);
		pivotquads.push_back(vertex);

		uvcoords = texmat * PVRTVec3(0.0f, 255.0f, 255.0f);
		vertex.word_index = 0;
		vertex.height_index = 1;
		vertex.u = (PVRTuint8)(uvcoords.x);
		vertex.v = (PVRTuint8)(uvcoords.y);
		pivotquads.push_back(vertex);

		uvcoords = texmat * PVRTVec3(255.0f, 255.0f, 255.0f);
		vertex.word_index = 1;
		vertex.height_index = 1;
		vertex.u = (PVRTuint8)(uvcoords.x);
		vertex.v = (PVRTuint8)(uvcoords.y);
		pivotquads.push_back(vertex);

		PVRTTriangle t0 = { index, index + 1, index + 3 };
		PVRTTriangle t1 = { index, index + 3, index + 2 };

		triangles.push_back(t0);
		triangles.push_back(t1);
	}		
}
/*!********************************************************************************************
 @Function		TriangulatePolygon
 @Input			coordinates         Coordinate array for the polygon.
 @Input			polygon             The polygon definition.
 @Output        triangle_coords     The resulting coordinates of the triangulation.
 @Output        triangle_indices    The resulting triangle indices of the polygon.
 @Return        True if the polygon could be triangulated, false otherwise.
 @Description	Triangulates a non-self-intersecting polygon.
***********************************************************************************************/
bool TriangulatePolygon(const PVRTCoordinateVector &coordinates, const PVRTPolygon &polygon, PVRTCoordinateVector &triangle_coords, PVRTTriangleVector &triangle_indices)
{
	// Copy the vertices, the index structure will be built on top of that set
	// without modification of the vertices
	triangle_coords = coordinates;

	// allocate and initialize list of Vertices in polygon 
	int num_vertices = (int)polygon.indices.size();
	if (num_vertices < 3) 
		return false;

	// Create a temporary storage area for the indices
	index_t *V = new index_t[num_vertices];

	// The polygon should be defined in counter-clockwise order
	if (CalculatePolygonArea(coordinates, polygon) > 0.0f)
	{
		for (int v=0; v < num_vertices; v++) 
			V[v] = polygon.indices[v];
	}
	// if not, reverse the index array
	else
	{
		for(int v=0; v < num_vertices; v++) 
			V[v] = polygon.indices[(num_vertices-1) - v];
	}

	// This counter should prevent endless loops (which only should happen in degenerate polygon cases)
	int loop_counter = num_vertices * 2; 

	// Remove nv-2 vertices, creating a triangle every iteration
	for (int v=num_vertices-1; num_vertices > 2; loop_counter--)
	{
		// We looped, there is an error in this polygon
		if (loop_counter <= 0)
			return false;

		// Get the indices for three consecutive vertices in the polygon forming a triangle
		int u = v % num_vertices; 
		v = (u + 1) % num_vertices; 
		int w = (v + 1) % num_vertices; 

		// Check if there is no point which lies within this triangle
		if (IsPolygonEar(coordinates, u, v, w, num_vertices, V))
		{			
			// No point found, that means it's an ear
			PVRTTriangle t = { V[u], V[v], V[w] };			
			triangle_indices.push_back(t);
			
			// Remove the triangle from the polygon by removing v
			for (int s=v; s < num_vertices-1; s++) 
				V[s] = V[s+1]; 
			num_vertices--;

			// Re-initialize the loop counter
			loop_counter = num_vertices * 2;
		}
	}

	delete [] V;

	return true;
}
/*!********************************************************************************************
 @Function		convert_texts
 @Input			layer          The map layer to extract the texts from.
 @Input			atlas          The texture atlas used for uv-coordinate calculation.
 @Output		pivotquads     The generated pivotquad vertex data.
 @Output		triangles      Triangle indices used for rendering of the pivotquads. 
 @Description	Generates pivotquads for the text strings which will be screen-space aligned
                when being rendered.
***********************************************************************************************/
void convert_texts(const PVRTMapLayer &layer, const PVRTTextureAtlas &atlas, PVRTPivotQuadVertexVector &pivotquads, PVRTTriangleVector &triangles)
{
	unsigned int numTotalLetters = 0;
	for (unsigned int j=0; j < layer.indexset.texts.size(); j++)
	{
		numTotalLetters += strlen(layer.indexset.texts[j].szName);
	}
	
	// Pre-allocate to prevent reallocations
	pivotquads.reserve(pivotquads.size() + numTotalLetters * 4);
	triangles.reserve(triangles.size() + numTotalLetters * 2);

	for (unsigned int j=0; j < layer.indexset.texts.size(); j++)
	{							
		const PVRTLinestrip &linestrip = layer.indexset.linestrips[layer.indexset.texts[j].index];
	
		string name(layer.indexset.texts[j].szName);
		unsigned int numLetters = name.length();

		float rand_pos = rand() / (float)RAND_MAX;
		// transform it to the range [0.2, 0.8] so that the streetnames are more in the middle of the street
		rand_pos = 0.2f + rand_pos * 0.6f;

		PVRTVec3 pos_3d = InterpolateLinestrip(layer.coordinates, linestrip, rand_pos);
		PVRTVec2 pos = PVRTVec2(pos_3d.x, pos_3d.y);

		int adjustedIndex = 0;
		unsigned int triangle_index = pivotquads.size();

		// Calculate the total width
		unsigned int word_width = 0;		
		for (unsigned int i=0; i < numLetters; i++)
			word_width += get_letter_spacing(name.at(i));
		const int anchor_index = word_width / 2;		

		size_t ordinal_pos;
		bool has_ordinal = contains_ordinal(name, ordinal_pos);

		for (unsigned int i=0; i < numLetters; i++)
		{					
			if (name.at(i) == ' ')
			{
				adjustedIndex += get_letter_spacing(name.at(i));				
				continue;
			}

			triangle_index = pivotquads.size();
			const int startIndex = adjustedIndex;
			int starty, endy;			
			
			// If it contains an ordinal and the current letter is one
			if (has_ordinal && ((i == ordinal_pos) || i == (ordinal_pos + 1)))
			{
				adjustedIndex += 2;
				starty = 2;
				endy = 5;
			}
			else
			{
				adjustedIndex += get_letter_spacing(name.at(i));				
				get_height_indices(name.at(i), starty, endy);				
			}
		
			string letter = name.substr(i, 1);

			PVRTMat3 texmat = atlas.GetTextureMatrix(letter);

			PVRTPivotQuadVertex vertex;
			vertex.origin = pos;

			PVRTVec3 uvcoords = texmat * PVRTVec3(0.0f, 0.0f, 255.0f);
			vertex.word_index = startIndex - anchor_index;
			vertex.height_index = starty;
			vertex.u = (PVRTuint8)(uvcoords.x);
			vertex.v = (PVRTuint8)(uvcoords.y);
			pivotquads.push_back(vertex);

			uvcoords = texmat * PVRTVec3(255.0f, 0.0f, 255.0f);
			vertex.word_index = adjustedIndex - anchor_index;
			vertex.height_index = starty;
			vertex.u = (PVRTuint8)(uvcoords.x);
			vertex.v = (PVRTuint8)(uvcoords.y);
			pivotquads.push_back(vertex);

			uvcoords = texmat * PVRTVec3(0.0f, 255.0f, 255.0f);

			vertex.word_index = startIndex - anchor_index;
			vertex.height_index = endy;
			vertex.u = (PVRTuint8)(uvcoords.x);
			vertex.v = (PVRTuint8)(uvcoords.y);
			pivotquads.push_back(vertex);

			uvcoords = texmat * PVRTVec3(255.0f, 255.0f, 255.0f);
			vertex.word_index = adjustedIndex - anchor_index;
			vertex.height_index = endy;
			vertex.u = (PVRTuint8)(uvcoords.x);
			vertex.v = (PVRTuint8)(uvcoords.y);
			pivotquads.push_back(vertex);

			PVRTTriangle t0 = { triangle_index, triangle_index + 1, triangle_index + 3 };
			PVRTTriangle t1 = { triangle_index, triangle_index + 3, triangle_index + 2 };

			triangles.push_back(t0);
			triangles.push_back(t1);				
		}
	}
}
bool TriangulatePolygon(const PVRTCoordinateVector &coordinates, const PVRTPolygon &polygon, PVRTCoordinateVector &triangle_coords, PVRTTriangleVector &triangles)
{
	unsigned int numPoints = polygon.indices.size();

	InitialiseTriangulationModule(numPoints,
								  2*numPoints,
								  NULL);

	int paths = 1;
	int pathlens[1] = { polygon.indices.size() };
	float maxDimension = -FLT_MAX;
	float *pCoordinates = new float[polygon.indices.size()*2];

	for (unsigned int i=0; i < polygon.indices.size(); i++)
	{
		PVRTVec3 coord = coordinates[polygon.indices[i]].position;
		pCoordinates[i*2] = coord.x;
		pCoordinates[i*2+1] = coord.y;

		maxDimension = PVRT_MAX(coord.x, maxDimension);
		maxDimension = PVRT_MAX(coord.y, maxDimension);
	}

	ExternalTrapStruct TrapezoidsResult;

	TRI_ERROR_TYPES status = BuildPolygonTrapeziation(NULL, //do all subpaths at once
									                  maxDimension,
											          // path data
											          paths,
											          pathlens,
											          pCoordinates,
											          // Specify a seed for the random number generator
											          // This isn't critcal if the processing is offline so just use 0
											          0,											 
											          // the resulting trap structure											 
											          &TrapezoidsResult);
	delete [] pCoordinates;
	if (!AnalyzeTriangulationError(status))
	{
		FreeTriangulationModuleMemory();
		return false;
	}

	int MaxFFRecursionDepth = 10000;
	int FillModeIsOddEven = 0;
	int numVertices = 0;
	float *pVertices = NULL;
	int numTriangles = 0;
	TriIndicesType *pTriangleIndices = NULL;

	numTriangles = OutputIndexedTriangles(&TrapezoidsResult,
										  MaxFFRecursionDepth,
										  FillModeIsOddEven,
										  true, 
										  &numVertices,
										  &pVertices,
										  &pTriangleIndices);

	for (int i=0; i < numTriangles; i++)
	{
		TriIndicesType triangle = pTriangleIndices[i];		
		PVRTVertex a = { PVRTVec3(pVertices[triangle.Ind[0]*2], pVertices[triangle.Ind[0]*2+1], 0.0f), PVRTVec2(0.0f, 0.0f) };
		PVRTVertex b = { PVRTVec3(pVertices[triangle.Ind[1]*2], pVertices[triangle.Ind[1]*2+1], 0.0f), PVRTVec2(0.0f, 0.0f) };
		PVRTVertex c = { PVRTVec3(pVertices[triangle.Ind[2]*2], pVertices[triangle.Ind[2]*2+1], 0.0f), PVRTVec2(0.0f, 0.0f) };

		const unsigned int index_start = triangle_coords.size();
		triangle_coords.push_back(a);
		triangle_coords.push_back(b);
		triangle_coords.push_back(c);

		PVRTTriangle tri = { index_start, index_start+1, index_start+2 };
		triangles.push_back(tri);
	}

	FreeTriangulationModuleMemory();

	return true;
}