#include <stdlib.h>
#include <math.h>
#  include <OpenGL/gl.h>
#  include <OpenGL/glu.h>
#  include <GLUT/glut.h>


float bijelo[] = {1.0f, 1.0f, 1.0f, 0.0f};
float crno[] = {0.0f, 0.0f, 0.0f};
float smedje[] = {238.0f / 255.0f, 154.0f / 255.0f, 73.0f / 255.0f};
float crveno[] = {1.0f, 0.0f, 0.0f};

double kut = 0.0;
int verzija = 0, nn = 16;
double pz =0.0;
double rx= 0.0;
void normiraj(double *v) {
	double d = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
	v[0] /= d; v[1] /= d; v[2] /= d;
} // normiraj

void vprodukt(double *v, double a0, double a1, double a2,
              double b0, double b1, double b2) {
	v[0] = a1 * b2 - a2 * b1;
	v[1] = a2 * b0 - a0 * b2;
	v[2] = a0 * b1 - a1 * b0;
} // vprodukt

void kocka(double a) {
	glBegin(GL_QUADS);
    glNormal3d(0.0, 0.0, -1.0);
    glVertex3d(0.0, 0.0, 0.0); glVertex3d(0.0, a, 0.0);
    glVertex3d(a, a, 0.0); glVertex3d(a, 0.0, 0.0);
	
    glNormal3d(0.0, 0.0, 1.0);
    glVertex3d(0.0, 0.0, a); glVertex3d(a, 0.0, a);
    glVertex3d(a, a, a); glVertex3d(0.0, a, a);
	glEnd();
	
	glBegin(GL_QUAD_STRIP);
    glNormal3d(0.0, -1.0, 0.0);
    glVertex3d(0.0, 0.0, a); glVertex3d(0.0, 0.0, 0.0);
    glVertex3d(a, 0.0, a); glVertex3d(a, 0.0, 0.0);
	
    glNormal3d(1.0, 0.0, 0.0);    
    glVertex3d(a, a, a); glVertex3d(a, a, 0.0);
	
    glNormal3d(0.0, 1.0, 0.0);
    glVertex3d(0.0, a, a); glVertex3d(0.0, a, 0.0);
	
    glNormal3d(-1.0, 0.0, 0.0);
    glVertex3d(0.0, 0.0, a); glVertex3d(0.0, 0.0, 0.0);
	glEnd();
} // kocka


void kvadar(double a, double b, double c) {
	glBegin(GL_QUADS);
    glNormal3d(0.0, 0.0, 1.0);
    glVertex3d(0.0, 0.0, 0.0); glVertex3d(0.0, b, 0.0);
	 glVertex3d(0, b, c);
    glVertex3d(0, 0, c);
	
    glNormal3d(0.0, 0.0, -1.0);
    glVertex3d(a, 0.0, 0); glVertex3d(a, 0.0, c);
    glVertex3d(a, b, c); glVertex3d(a, b, 0);
	glEnd();
	
	glBegin(GL_QUAD_STRIP);
    glNormal3d(0.0, 1.0, 0.0);
    glVertex3d(0.0, 0.0, 0.0); glVertex3d(a, 0.0, 0.0);
    glVertex3d(0, b, 0); glVertex3d(a, b, 0.0);
	
    glNormal3d(1.0, 0.0, 0.0);    
    glVertex3d(0, b, c); glVertex3d(a, b, c);
	
    glNormal3d(0.0, 1.0, 0.0);
    glVertex3d(0.0, 0, c); glVertex3d(a, 0, c);
	
    glNormal3d(-1.0, 0.0, 0.0);
    glVertex3d(0.0, 0.0, 0.0); glVertex3d(0.0, b, 0.0);
	glEnd();
} // kvadar


void polukugla(double R) {
	double ntheta = 20;
	double nphi=20;
	double t, r, z;
	double theta, step_theta = M_PI / ntheta;
	double r1, r2, z1, z2;
	int i;
	
	theta = M_PI / 2.0 - step_theta;
	r = R * cos(theta);
	z = R * sin(theta);
	
	for(theta = M_PI / 2.0 - 2.0 * step_theta; theta > -M_PI / 2.0;
		theta -= step_theta) {
		r1 = R * cos(theta); r2 = R * cos(theta + step_theta);
		z1 = R * sin(theta); z2 = R * sin(theta + step_theta);  
		
		glBegin(GL_QUAD_STRIP);
		t = 0.0; 
		for(i = 0; i <= nphi/2; i++) {
			glNormal3d(r2 * cos(t) / R, r2 * sin(t) / R, z2 / R);
			glVertex3d(r2 * cos(t), r2 * sin(t), z2);			
			glNormal3d(r1 * cos(t) / R, r1 * sin(t) / R, z1 / R);
			glVertex3d(r1 * cos(t), r1 * sin(t), z1);
			t += 2.0 * M_PI / nphi;
		}
		glEnd();
	}
	
} // polukugla

void kugla(double R, int nphi, int ntheta) {
	double t, r, z;
	double theta, step_theta = M_PI / ntheta;
	double r1, r2, z1, z2;
	int i;
	
	// bliÅ¾a kapica
	theta = M_PI / 2.0 - step_theta;
	r = R * cos(theta);
	z = R * sin(theta);
	glBegin(GL_TRIANGLE_FAN);
    glNormal3d(0.0, 0.0, 1.0);
    glVertex3d(0.0, 0.0, R);
    t = 0.0;
    for(i = 0; i <= nphi; i++) {
		glNormal3d(r * cos(t) / R, r * sin(t) / R, z / R);      
		glVertex3d(r * cos(t), r * sin(t), z);
		t += 2.0 * M_PI / nphi;
    }
	glEnd();
	
	// plaÅ¡t
	for(theta = M_PI / 2.0 - 2.0 * step_theta; theta > -M_PI / 2.0;
		theta -= step_theta) {
		r1 = R * cos(theta); r2 = R * cos(theta + step_theta);
		z1 = R * sin(theta); z2 = R * sin(theta + step_theta);  
		
		glBegin(GL_QUAD_STRIP);
		t = 0.0; 
		for(i = 0; i <= nphi; i++) {
			glNormal3d(r2 * cos(t) / R, r2 * sin(t) / R, z2 / R);
			glVertex3d(r2 * cos(t), r2 * sin(t), z2);
			glNormal3d(r1 * cos(t) / R, r1 * sin(t) / R, z1 / R);
			glVertex3d(r1 * cos(t), r1 * sin(t), z1);
			t += 2.0 * M_PI / nphi;
		}
		glEnd();
	}
	
	// dalja kapica
	theta = -M_PI / 2.0 + step_theta;
	r = R * cos(theta);
	z = R * sin(theta);
	glBegin(GL_TRIANGLE_FAN);
    glNormal3d(0.0, 0.0, -1.0);
    glVertex3d(0.0, 0.0, -R);
    t = 0.0;
    for(i = 0; i <= nphi; i++) {
		glNormal3d(r * cos(t) / R, r * sin(t) / R, z / R);
		glVertex3d(r * cos(t), r * sin(t), z);
		t -= 2.0 * M_PI / nphi;
    }
	glEnd();
} // kugla


void valjak (double r, double v) {
	int i;
	glBegin (GL_TRIANGLE_FAN); 
	glNormal3d(0.0, 0.0, -1.0);
	glVertex3d(0.0, 0.0, v);      
	double t;
	
	for(t = 0.0; t < 2.0 * M_PI+1; t += M_PI/10) {
		glVertex3d(r * cos(t), r * sin(t),v);
	}
	glVertex3d(0.0, 0.0, v);      
	glEnd();
	
	glBegin (GL_TRIANGLE_FAN); 
	glNormal3d(0.0, 0.0, -1.0);
	glVertex3d(0.0, 0.0, 0.0);  
	for(t = 2.0 * M_PI+1; t > 0.0; t -= M_PI/10) {	
		glVertex3d(r * cos(t), r * sin(t),0);
	}
	glEnd();   
	glBegin (GL_QUAD_STRIP); 
	
	for(t = 2.0 * M_PI+1; t > 0.0; t -= M_PI/10) {		
		glNormal3d(cos(t), sin(t), 0.0);
		glVertex3d(r * cos(t), r * sin(t),0);
		glNormal3d(cos(t), sin(t), 0.0);
		glVertex3d(r * cos(t), r * sin(t),v);
	}
	glEnd();   
	
} 




void stozac(double r, double h, int n) {
	double t, s, v[] = {0.0, 0.0, 0.0};
	int i;
	
	// baza stožca
	glBegin(GL_TRIANGLE_FAN);
    glNormal3d(0.0, 0.0, 1.0); // normala je u smjeru -z za sve trokute
    glVertex3d(0.0, 0.0, 0.0); // središte baze je u ishodištu
    t = 0.0;
    for(i = 0; i <= n; i++) {
		glVertex3d(r * cos(t), r * sin(t), 0.0);
		t += 2.0 * M_PI / n;
    }
	glEnd();
	
	glBegin(GL_TRIANGLE_STRIP);
    t = 2.0 * M_PI;
    for(i = 0; i <= n; i++) {
		vprodukt(v, -r * cos(t), -r * sin(t), h, 
				 -cos(t + M_PI / 2.0), -sin(t + M_PI / 2.0), 0.0);
		normiraj(v);
		glNormal3dv(v);
		glVertex3d(r * cos(t), r * sin(t), 0.0);
		t -= M_PI / n; // samo pola koraka
		
		vprodukt(v, -r * cos(t), -r * sin(t), h, 
				 -cos(t + M_PI / 2.0), -sin(t + M_PI / 2.0), 0.0);
		normiraj(v);
		glNormal3dv(v); // vektor normale u vrhu je okomit na bazu trokuta
		glVertex3d(0.0, 0.0, h);
		t -= M_PI / n; // dopuna do punog koraka
    }
	glEnd();
} // stozac

void svjetlo0() {
	float pozicija[] = {0.0f, 0.0f, 0.0f, 1.0f};
	// četvrti parametar postavljen na 1.0f definira "positional light"
	// na poziciji koju određuju prva tri parametra
	
	glLightfv(GL_LIGHT0, GL_DIFFUSE, bijelo);
	glLightfv(GL_LIGHT0, GL_SPECULAR, bijelo);
	glLightfv(GL_LIGHT0, GL_POSITION, pozicija);
} // svjetlo0

void iscrtaj(void) {
	double r = 6.0, h = 18.0; // polumjer baze i visina stošca
	
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	// kamera gleda pola visine stošca iznad ishodišta
	gluLookAt(0.0, 40.0, 0.0, 0.0, 0.0, h / 2.0, 0.0, 0.0, 1.0);
	glPushMatrix(); // pamtimo da smo u ishodištu
    // postavljamo svjetlo 0 na odgovarajuću poziciju
    glTranslated(-8.0, 20.0, 3.0);
    svjetlo0();
    // položaj svjetla 0 označit ćemo bijelom kockicom
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, bijelo);	
    glMaterialfv(GL_FRONT, GL_EMISSION, bijelo);
    kocka(0.5);
    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, crno);
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, crveno);

	glPopMatrix(); // vraćamo se u ishodište
	glTranslated(-4,0,0);

	glTranslated(0,0,pz);
	glRotated(60,1,0,0);
	glRotated(rx,0,1,0);
	valjak(1,12);
	glPushMatrix();
	glTranslated(0,0,4);
	kvadar(10,0,3);
	glPopMatrix();
	glPushMatrix();
	glTranslated(5,5,5);
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, smedje);

	kugla(5,50,50);
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, crveno);

	glTranslated(0,4,0);
	valjak(1,9);
	glPopMatrix();
	glPushMatrix();
	glTranslated(5,9,5);
	glRotated(270,1,0,0);
	stozac(1,3,16);
	glRotated(kut,0,0,1);
	glTranslated(-10,0,2);
	glRotated(90,1,0,0);
	kvadar(20,0,1);
	glTranslated(10,0,10);
	glRotated(90,0,1,0);
	kvadar(20,0,1);
	glPopMatrix();
	glTranslated(10,0,0);
	valjak(1,12);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, bijelo);
	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0); 
	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);				
	glutSwapBuffers();
} // iscrtaj

void skaliraj(int w, int h) {
	double xmin = -10.0, xmax = 10.0;
	double xrange = xmax - xmin;
	double yrange = h * xrange / w;	
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glFrustum(xmin, xmax, -yrange / 2.0, yrange / 2.0, 20.0, 50.0);
} // skaliraj

void tipka(unsigned char c, int x, int y) {
	if(c == 'q') exit(0);
	if(c == 's') glShadeModel(GL_SMOOTH);
	if(c == 'D') glEnable(GL_DEPTH_TEST);
	if(c == 'd') glDisable(GL_DEPTH_TEST);
	if(c == '0') glEnable(GL_LIGHT0);
	if(c == '=') glDisable(GL_LIGHT0);
} // tipka

void strelice(int c, int x, int y) {
	if(c == GLUT_KEY_UP) pz += 0.5;
	if(c == GLUT_KEY_DOWN) pz -= 0.5;
	if(c == GLUT_KEY_LEFT) rx -=4;
	if(c == GLUT_KEY_RIGHT) rx +=4;

	glutPostRedisplay();
} // strelice


void rotiraj(void) {
	kut += 1;
		
	glutPostRedisplay();} // rotiraj


int main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB);
	
	glutInitWindowSize(640, 480);
	glutCreateWindow("Helikopter");
	
	glShadeModel(GL_FLAT);
	glEnable(GL_DEPTH_TEST);
	glClearColor(0.0, 0.0, 0.0, 0.0);
	
	glEnable(GL_LIGHTING); // omogućava osvjetljenje
	glEnable(GL_LIGHT0); // uključuje svjetlo 0
	
	glutDisplayFunc(iscrtaj);
	glutReshapeFunc(skaliraj);
	glutKeyboardFunc(tipka);
	glutSpecialFunc(strelice);

	glutIdleFunc(rotiraj);
	
	glutMainLoop();
	return 0;
} // main


