#include <GL/glut.h>
#include "sector.h"
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

#define FOV 60
#define ALWAYS_DRAW FALSE
// #define __LIGHTING__

float cam_x = 0;
float cam_y = 300;
float cam_z = 60;
float eye_x = 0;
float eye_y = 210;
float eye_z = 0;

float z;
int x,y, c, d, size;
int sun, sun_list;
float progress = 0;

GLfloat sun_position[4] = { -200.0, -200.0, 100.0, 1.0 };
GLfloat sun_ambi[4] = { 0.3, 0.3, 0.3, 1.0 };
GLfloat sun_diff[4] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat sun_spec[4] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat sun_dire[3] = { 10.0,10.0,-0.0 };

GLfloat mat_ambi[4] = { 0.6, 0.6, 0.6, 1.0 };
GLfloat mat_diff[4] = { 0.6, 0.6, 0.6, 1.0 };
GLfloat mat_spec[4] = { 1.0, 1.0, 1.0, 1.0 };

GLfloat global_ambient[4] = { 0.1, 0.1, 0.1, 1.0 };

float COLORS[20][3] = { 
	0.2f,0.7f,0.2f,
	0.4f,0.8f,0.4f,
	0.6f,0.8f,0.6f,
	0.85f,0.85f,0.7f,
	0.85f,0.9f,0.8f,
	0.9f,0.9f,0.9f,
	1.0f,1.0f,1.0f,
	1.0f,1.0f,1.0f,
	1.0f,1.0f,1.0f,
	1.0f,1.0f,1.0f,
	1.0f,1.0f,1.0f,
	1.0f,1.0f,1.0f,
	1.0f,1.0f,1.0f,
	1.0f,1.0f,1.0f
};

Earth* earth;

void init() {
	glClearColor(0.9,0.9,0.95,1.0);
//	glClearDepth(1.0);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
}

void myVertex3f(float x, float y, float z) {
	if (z<-2.0f) glColor3f(0.4f,0.4f,0.9f);
	else 	if (z<2.5f) 
		  glColor3f((float)(rand()%10)/100.0f + 0.3f,
				 		(float)(rand()%10)/100.0f + 0.6f,
						(float)(rand()%10)/100.0f + 0.3);
	else {	
		glColor3f(COLORS[(int) (z/3)][0],
					 	COLORS[(int) (z/3)][1],
					 	COLORS[(int) (z/3)][2]);
	}
	glVertex3f(x,y,z);
}

void display() {
	glPushMatrix();
	gluLookAt(cam_x, cam_y, cam_z, eye_x, eye_y, eye_z, 0.0f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	if (!earth) {
		printf("Earth is NULL!\n");
	} else if (!earth->sector[0]) {
		printf("Sector 0 is NULL!\n");
	} else d = 1; 


#ifdef __LIGHTING__
	if (!sun_list) {
		sun_list = glGenLists(1);
		glNewList(sun_list,GL_COMPILE);
		glLightfv(GL_LIGHT0,GL_POSITION, sun_position);
		glLightfv(GL_LIGHT0,GL_AMBIENT, sun_ambi);
		glLightfv(GL_LIGHT0,GL_DIFFUSE, sun_diff);
		glLightfv(GL_LIGHT0,GL_SPECULAR, sun_diff);
		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambi);
		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diff);
		glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_diff);
		glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 100.0);
		// glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);
		glEndList();
	} else glCallList(sun_list);
#endif
	if (d) for (c=0;c<N_SECTORS;c++) {
		if ((!earth->sector[c]->dirty) && (earth->sector[c]->display_list)) {
			glTranslatef(-0.5*size,earth->sector[c]->y_offset,0.0);		
			glCallList(earth->sector[c]->display_list);
			glTranslatef(0.5*size,-earth->sector[c]->y_offset,0.0);
			continue;
		}
		if (!earth->sector[c]->display_list) {
		//	printf("Creating display list for sector %i...",(c+1));
			earth->sector[c]->display_list = glGenLists(1);
			if (earth->sector[c]->display_list) printf("done.\n");
		//	else printf("failed.\n");
		}
		if (!earth->sector[c]->display_list) continue;
	//	printf("Compiling new display list for sector %i...\n",(c+1)); fflush(stdout);
		glNewList(earth->sector[c]->display_list,GL_COMPILE);
		for (y=0;y<SECTOR_FIELDS-1;y++) {
			glBegin(GL_TRIANGLE_STRIP);
			myVertex3f(0 * SCHRITT, (y+1)*SCHRITT, earth->sector[c]->field[0][y+1]);
			myVertex3f(0 * SCHRITT, y*SCHRITT, earth->sector[c]->field[0][y]);
			myVertex3f(1 * SCHRITT, (y+1)*SCHRITT, earth->sector[c]->field[1][y+1]);
			myVertex3f(1 *SCHRITT, y*SCHRITT, earth->sector[c]->field[1][y]);
			for (x=0;x<SECTOR_FIELDS-1;x++) {
				myVertex3f((x+1)*SCHRITT, (y+1)*SCHRITT, earth->sector[c]->field[x+1][y+1]);
				myVertex3f((x+1)*SCHRITT, y*SCHRITT, earth->sector[c]->field[x+1][y]);
		  	}
			glEnd();
		}
		glEndList();
		printf("done.\n");
		earth->sector[c]->dirty=0;
	}
	glPopMatrix();
	glFlush();
	glutSwapBuffers();
}

void reshape(int w, int h) {
	glEnable(GL_LINE_SMOOTH);
	glShadeModel(GL_SMOOTH);
	glEnable(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);
//	glDepthFunc(GL_LESS);
	glPolygonMode(GL_FRONT, GL_FILL);
//	glEnable(GL_ALPHA_TEST);
//	glEnable(GL_BLEND);
//	glDepthMask(GL_TRUE);
//	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	glEnable(GL_NORMALIZE);
	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);

#ifdef __LIGHTING__
	glEnable(GL_COLOR_MATERIAL);
//	glColorMaterial(GL_FRONT,GL_DIFFUSE);
	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
	glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
#endif

	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(FOV,((float)w/(float)h),0.1f,300.0f);
	glMatrixMode(GL_MODELVIEW);
}

void tour() {
	Sector *hsec;
	while (1) {
		cam_y -=4;
		eye_y -=4;
		progress += 4;
		if (progress > size) {
	//		printf("Progess!\n");fflush(stdout);	
			hsec = earth->sector[0];
			earth->sector[0] = earth->sector[1];
			earth->sector[1] = earth->sector[2];
			earth->sector[2] = hsec;
			erdpunkte_berechnen(hsec);
			hsec->dirty = 1;
			hsec->y_offset = earth->sector[1]->y_offset-size;
			join_sectors(earth->sector[1],hsec,SOUTH,15);
			progress -= size;	
		}	
		display();
	}
}

void keyboard(unsigned char key, int x, int y) {
	if (key!='w') return;
	tour();
}

int main(int argc, char **argv) {
	int c;
	glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(640,480);
	glutInitWindowPosition(0,0);
	glutCreateWindow("Terrain");
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutKeyboardFunc(keyboard);
	init();
	earth = earth_new();
	if (!earth) { printf("Konnte keine Erde erschaffen!\n."); exit(-1); } 
	size = (SECTOR_FIELDS-1) * SCHRITT;
	for (c=0;c<N_SECTORS;c++)
		earth->sector[c]->y_offset = (float)(-c) * size;
	glutMainLoop();
	return 0;
}


