/// Copyright (c) 2009 Ruben Penalva. All rights reserved.
/// Redistribution and use in source and binary forms, with or without modification, 
/// are permitted provided that the following conditions are met:
///    1. Redistributions of source code must retain the above copyright notice, this 
///    list of conditions and the following disclaimer.
///    2. Redistributions in binary form must reproduce the above copyright notice,
///    this list of conditions and the following disclaimer in the documentation and/or
///    other materials provided with the distribution.
///    3. The name of the author may not be used to endorse or promote products derived
///    from this software without specific prior written permission.
///
/// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
/// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
/// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 
/// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
/// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
/// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
/// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
/// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <stdlib.h>
#include <string>
#include <vector>

#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include "triangle.h"

const int g_numberofpoints = 10;
REAL g_points[] = {0.0, 0.0, 0.0, 5.0, 1.0, 3.0, 1.0, 4.0, 2.0, 3.0,
				   2.0, 4.0, 3.0, 2.0, 4.0, 1.0, 5.0, 0.0, 5.0, 5.0};
std::vector<int> g_indices;

void InitializeOpengl(int width, int height)
{	
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0.5, 0.5, 0.7, 0.0);
    glColor3f(1.0, 1.0, 1.0);

	glTranslatef(0.0f,0.0f,-10.0f); 
	glEnable(GL_LINE_SMOOTH);
    glDisable(GL_CULL_FACE);
    glFrontFace(GL_CCW);

    glDisable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
	
	glViewport(0, 0, width, height);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	// Calculate The Aspect Ratio Of The Window
	gluPerspective(45.0f,(GLfloat)width/(GLfloat)height, 0.1f, 100.0f);

	glMatrixMode(GL_MODELVIEW);	
	glLoadIdentity();

	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

}

void Triangulate(void)
{
	struct triangulateio in, out;
	memset(&in, 0, sizeof(triangulateio));
	memset(&out, 0, sizeof(triangulateio));

	/// Define input points
	int pointMarkers[] = {2, 2, 2, 2, 3, 3, 3, 3, 4, 4};
	in.numberofpoints = g_numberofpoints;
	in.pointlist = g_points;
	in.pointmarkerlist = pointMarkers;

	/// Define segments
	int segments[] = {0, 8, 8, 9, 9, 1, 1, 0, 2, 4, 4, 5, 5, 3, 3, 2, 6, 7};
	int segmentMarkers[] = {2, 2, 2, 2, 3, 3, 3, 3, 4};
	in.numberofsegments = 9;
	in.segmentlist = segments;
	in.segmentmarkerlist = segmentMarkers;

	/// Define holes
	REAL holes[] = {1.5, 3.5};
	in.numberofholes = 1;
	in.holelist = holes;
#ifdef _DEBUG
	triangulate("pz", &in, &out, 0);
#else
	triangulate("pzQ", &in, &out, 0);
#endif

	int trianglesCount = out.numberoftriangles * 3;
	for (int i = 0; i < trianglesCount; ++i)
	{
		g_indices.push_back(out.trianglelist[i]);
	}

	free(out.pointlist);
	free(out.pointmarkerlist);
	free(out.trianglelist);
	free(out.neighborlist);
	free(out.segmentlist);
	free(out.segmentmarkerlist);
}
void DisplayFunc(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glBegin(GL_TRIANGLES);
		int indicesCount = g_indices.size();
		for (int i = 0; i < indicesCount; i += 3)
		{
			int indexA = g_indices[i] * 2;
			glVertex3f(g_points[indexA], g_points[indexA + 1], -15.0f);

			int indexB = g_indices[i + 1] * 2;
			glVertex3f(g_points[indexB], g_points[indexB + 1], -15.0f);

			int indexC = g_indices[i + 2] * 2;
			glVertex3f(g_points[indexC], g_points[indexC + 1], -15.0f);
		}
	glEnd();

	glutSwapBuffers();
}

int main(int argc, char** argv)
{
	const int windowSize[2] = {800, 600};
	const char* windowName = "Simple CDT";
	glutInit(&argc, argv);
	
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowSize(windowSize[0], windowSize[1]);
	glutCreateWindow(windowName);
	glutDisplayFunc(DisplayFunc);

	InitializeOpengl(windowSize[0], windowSize[1]);

	Triangulate();

	glutMainLoop();

	return 0;
}