#include<gl/glut.h>
#include<gl/gl.h>
#include<gl/glu.h>
#include<math.h>
#include<stdio.h>
typedef struct strpoint3D{
	float x,y,z;
} point3D;

typedef struct strtriangle{
	int n1,n2,n3;
}triangle;

typedef struct strTetraedro {
	float alphaX,alphaY,alphaZ;
	point3D points[4];
} Tetraedro;

void ChangeSize(int w, int h){
	if(h==0) h=1;
	glViewport(0,0,w,h);
	float aspect_ratio=float(w)/float(h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0f, aspect_ratio, 1.0, 50.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

Tetraedro tetra;
unsigned char axis='0';
bool wireframe=false,moving=false;
GLuint moving_vertex;

void InizializzaSolidi(){
	int radius=5;
	point3D p;
	int side=0;
	for(side=0;side<3;side++){
		p.x=radius*cos(2*side*3.1416/3);
		p.z=radius*sin(2*side*3.1416/3);
		p.y=0;
		tetra.points[side]=p;
	}
	p.x=p.z=0;
	p.y=5;
	tetra.points[3]=p;
}

void DrawScene(){
	glInitNames();
	glPushName(0);
	int i=0;
	glMatrixMode(GL_MODELVIEW);
	if(wireframe==true)
		glPolygonMode(GL_FRONT,GL_LINE);
	else
		glPolygonMode(GL_FRONT,GL_FILL);
	glEnable(GL_CULL_FACE);
	glLoadIdentity();
	glTranslatef(0,0,-30);
	glClearColor(0.0,0.0,0.0,1.0);
	glClear(GL_COLOR_BUFFER_BIT);
	switch(axis){
	case 'x':
		glRotatef(90,0.0f,1.0f,0.0f);
		break;
	case 'y':
		glRotatef(-90,1.0f,0.0f,0.0f);
		break;
	}
	glBegin(GL_LINES);
	/*asse x*/
	glColor3f(1.0,0.0,0.0);
	glVertex3f(0.0f,0.0f,0.0f);
	glVertex3f(10.0f,0.0f,0.0f);
	/*asse y*/
	glColor3f(0.0,1.0,0.0);
	glVertex3f(0.0f,0.0f,0.0f);
	glVertex3f(0.0f,10.0f,0.0f);
	/*asse z*/
	glColor3f(0.0,0.0,1.0);
	glVertex3f(0.0f,0.0f,0.0f);
	glVertex3f(0.0f,0.0f,10.0f);
	glEnd();
	
	glPushMatrix();
	glRotatef(tetra.alphaZ,0,0,1);
	glRotatef(tetra.alphaY,0,1,0);
	glRotatef(tetra.alphaX,1,0,0);
	glColor3f(0,1.0f,1.0f);
	if(wireframe==true){
		glPushMatrix();
		glTranslatef(tetra.points[3].x,tetra.points[3].y,tetra.points[3].z);
		glLoadName(3);
        glutSolidSphere(0.5,50,50);
		glPopMatrix();
		glPushMatrix();
		glTranslatef(tetra.points[0].x,tetra.points[0].y,tetra.points[0].z);
		glLoadName(0);
        glutSolidSphere(0.5,50,50);
		glPopMatrix();
		glPushMatrix();
		glTranslatef(tetra.points[1].x,tetra.points[1].y,tetra.points[1].z);
		glLoadName(1);
        glutSolidSphere(0.5,50,50);
		glPopMatrix();
		glPushMatrix();
		glTranslatef(tetra.points[2].x,tetra.points[2].y,tetra.points[2].z);
		glLoadName(2);
        glutSolidSphere(0.5,50,50);
		glPopMatrix();
	}
	glBegin(GL_TRIANGLES);		
		glVertex3f(tetra.points[3].x,tetra.points[3].y,tetra.points[3].z);
		glVertex3f(tetra.points[0].x,tetra.points[0].y,tetra.points[0].z);
		glVertex3f(tetra.points[1].x,tetra.points[1].y,tetra.points[1].z);
		glColor3f(0.33f,0.0f,1.0f);
		glVertex3f(tetra.points[3].x,tetra.points[3].y,tetra.points[3].z);
		glVertex3f(tetra.points[1].x,tetra.points[1].y,tetra.points[1].z);
		glVertex3f(tetra.points[2].x,tetra.points[2].y,tetra.points[2].z);
		glColor3f(0.66f,1.0f,0.0f);
		glVertex3f(tetra.points[3].x,tetra.points[3].y,tetra.points[3].z);
		glVertex3f(tetra.points[2].x,tetra.points[2].y,tetra.points[2].z);
		glVertex3f(tetra.points[0].x,tetra.points[0].y,tetra.points[0].z);
		glColor3f(0.99f,1.0f,1.0f);
		glVertex3f(tetra.points[2].x,tetra.points[2].y,tetra.points[2].z);
		glVertex3f(tetra.points[1].x,tetra.points[1].y,tetra.points[1].z);
		glVertex3f(tetra.points[0].x,tetra.points[0].y,tetra.points[0].z);
		glEnd();
		
		glPopMatrix();
	glutSwapBuffers();
}


#define BUFFER_LENGTH 64
void ProcessSelection(int xPos, int yPos)	{
	GLfloat fAspect;
	static GLuint selectBuff[BUFFER_LENGTH];
	GLint hits, viewport[4];
	glSelectBuffer(BUFFER_LENGTH, selectBuff);
	glGetIntegerv(GL_VIEWPORT, viewport);
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glRenderMode(GL_SELECT);
	glLoadIdentity();
	gluPickMatrix(xPos, viewport[3] - yPos, 5,5, viewport);
	fAspect = (float)viewport[2] / (float)viewport[3];
	gluPerspective(45.0f, fAspect, 1.0, 50.0);
	DrawScene();
	hits = glRenderMode(GL_RENDER);
	moving_vertex=selectBuff[3];
	moving=true;
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	}


void MouseCallback(int button, int state, int x, int y)	{
	if(button==GLUT_LEFT_BUTTON && state==GLUT_DOWN && wireframe==true)
		ProcessSelection(x, y);
}

void KeyboardFunc(unsigned char k, int x, int y){
	switch(k){
		case 'w':
			wireframe=!wireframe;
			break;
		case '1':
			tetra.alphaX+=5;
			if(tetra.alphaX>=360)
				tetra.alphaX=0;
			break;
		case '2':
			tetra.alphaY+=5;
			if(tetra.alphaY>=360)
				tetra.alphaY=0;
			break;
		case '3':
			tetra.alphaZ+=5;
			if(tetra.alphaZ>=360)
				tetra.alphaZ=0;
			break;
		default:
			axis=k;
	}
	glutPostRedisplay();
}

void SpecialKeys(int k, int x, int y){
	if(moving==true)
		switch(k){
		case GLUT_KEY_UP:
			switch(axis){
				case 'x':
					tetra.points[moving_vertex].y+=1;
					break;
				case 'y':
					tetra.points[moving_vertex].x+=1;
					break;
				default:
					tetra.points[moving_vertex].y+=1;
		}
				glutPostRedisplay();
			break;
		case GLUT_KEY_DOWN:
			switch(axis){
				case 'x':
					tetra.points[moving_vertex].y-=1;
					break;
				case 'y':
					tetra.points[moving_vertex].x-=1;
					break;
				default:
					tetra.points[moving_vertex].y-=1;
			}
				glutPostRedisplay();
			break;
	}
}

int main(){
	InizializzaSolidi();
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(640,480);
	glutCreateWindow("esame");
	glutDisplayFunc(DrawScene);
	glutReshapeFunc(ChangeSize);
	glutMouseFunc(MouseCallback);
	glutKeyboardFunc(KeyboardFunc);
	glutSpecialFunc(SpecialKeys);
	glutMainLoop();
}