
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>

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

double kut = 0.0;
int verzija = 0, nn = 16;

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) {
  glMaterialfv(GL_FRONT, GL_DIFFUSE, crno);
  glMaterialfv(GL_FRONT, GL_EMISSION, bijelo);

  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();

  glMaterialfv(GL_FRONT, GL_EMISSION, crno);
} // kocka

void stozacV0(double r, double h, int n) {
  double t;
  int i;

  glBegin(GL_TRIANGLE_FAN);
    glNormal3d(0.0, -1.0, 0.0);
    glVertex3d(0.0, 0.0, 0.0);
    t = 0.0;
    for(i = 0; i <= n; i++) {
      glVertex3d(r * cos(t), 0.0, r * sin(t));
      t += 2.0 * M_PI / n;
    }
    glVertex3d(r, 0.0, 0.0);
  glEnd();

  glBegin(GL_TRIANGLE_FAN);
    glNormal3d(0.0, 1.0, 0.0);
    glVertex3d(0.0, h, 0.0);
    t = 0.0;
    for(i = 0; i <= n; i++) {
      glNormal3d(cos(t), 0.0, sin(t));
      glVertex3d(r * cos(t), 0.0, r * sin(t));
      t -= 2.0 * M_PI / n;
    }
  glEnd();
} // stozacV0

void stozacV1(double r, double h, int n) {
  double t, v[] = {0.0, 0.0, 0.0};
  int i;

  glBegin(GL_TRIANGLE_FAN);
    glNormal3d(0.0, -1.0, 0.0);
    glVertex3d(0.0, 0.0, 0.0);
    t = 0.0;
    for(i = 0; i <= n; i++) {
      glVertex3d(r * cos(t), 0.0, r * sin(t));
      t += 2.0 * M_PI / n;
    }
    glVertex3d(r, 0.0, 0.0);
  glEnd();

  glBegin(GL_TRIANGLE_FAN);
    glNormal3d(0.0, 1.0, 0.0);
    glVertex3d(0.0, h, 0.0);
    t = 0.0;
    for(i = 0; i <= n; i++) {
      vprodukt(v, r * cos(t), -h, r * sin(t),
        cos(t - M_PI / 2.0), 0.0, sin(t - M_PI / 2.0));
      normiraj(v);
      glNormal3dv(v);
      glVertex3d(r * cos(t), 0.0, r * sin(t));
      t -= 2.0 * M_PI / n;
    }
  glEnd();
} // stozacV1

void stozacV2(double r, double h, int n) {
  double t, v[] = {0.0, 0.0, 0.0};
  int i;

  glBegin(GL_TRIANGLE_FAN);
    glNormal3d(0.0, -1.0, 0.0);
    glVertex3d(0.0, 0.0, 0.0);
    t = 0.0;
    for(i = 0; i <= n; i++) {
      glVertex3d(r * cos(t), 0.0, r * sin(t));
      t += 2.0 * M_PI / n;
    }
    glVertex3d(r, 0.0, 0.0);
  glEnd();

  glBegin(GL_TRIANGLE_STRIP);
 
    t = 0.0;
    for(i = 0; i <= n; i++) {
      vprodukt(v, r * cos(t), -h, r * sin(t),
        cos(t - M_PI / 2.0), 0.0, sin(t - M_PI / 2.0));
      normiraj(v);
      glNormal3dv(v);
      glVertex3d(0.0, h, 0.0);
      glVertex3d(r * cos(t), 0.0, r * sin(t));
      t -= 2.0 * M_PI / n;
    }
  glEnd();
} // stozacV2

void stozacV3(double r, double h, int n) {
  double t, s, v[] = {0.0, 0.0, 0.0};
  int i;

  glBegin(GL_TRIANGLE_FAN);
    glNormal3d(0.0, -1.0, 0.0);
    glVertex3d(0.0, 0.0, 0.0);
    t = 0.0;
    for(i = 0; i <= n; i++) {
      glVertex3d(r * cos(t), 0.0, r * sin(t));
      t += 2.0 * M_PI / n;
    }
    glVertex3d(r, 0.0, 0.0);
  glEnd();

  glBegin(GL_TRIANGLE_STRIP);
    t = 0.0;
    for(i = 0; i <= n; i++) {
      vprodukt(v, r * cos(t), -h, r * sin(t),
        cos(t - M_PI / 2.0), 0.0, sin(t - M_PI / 2.0));
      normiraj(v);
      glNormal3dv(v);
      glVertex3d(r * cos(t), 0.0, r * sin(t));
      t -= M_PI / n;

      vprodukt(v, r * cos(t), -h, r * sin(t),
        cos(t - M_PI / 2.0), 0.0, sin(t - M_PI / 2.0));
      normiraj(v);
      glNormal3dv(v);
      glVertex3d(0.0, h, 0.0);
      t -= M_PI / n;
    }
  glEnd();
} // stozacV3

void svjetlo0() {
  float pozicija[] = {0.0, 0.0, 0.0, 1.0 };

  glLightfv(GL_LIGHT0, GL_DIFFUSE, bijelo);
  glLightfv(GL_LIGHT0, GL_SPECULAR, bijelo);
  glLightfv(GL_LIGHT0, GL_POSITION, pozicija);
} // svjetlo0

void slikaj(void) {
  double r = 6.0, h = 18.0;

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glColor3d(1.0, 1.0, 0.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  gluLookAt(0.0, 0.0, 40.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

  glPushMatrix();
    glTranslated(8.0, 6.0, 18.0);
    svjetlo0();
    kocka(0.5);
  glPopMatrix();

  glTranslated(0.0, 0.0, r);
  glRotated(kut, 0.0, h, -r);
  glTranslated(0.0, 0.0, -r);

  glMaterialfv(GL_FRONT, GL_DIFFUSE, smedje);
  glMaterialfv(GL_FRONT, GL_SPECULAR, bijelo);
  glMaterialf(GL_FRONT, GL_SHININESS, 20.0); 

  switch(verzija) {
    case 0 : stozacV0(r, h, nn); break;
    case 1 : stozacV1(r, h, nn); break;
    case 2 : stozacV2(r, h, nn); break;
    case 3 : stozacV3(r, h, nn);
  }

  glutSwapBuffers();
} // slikaj

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 / 4.0, 3.0 * yrange / 4.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 == 'f') glShadeModel(GL_FLAT);
  if(c == 'D') glEnable(GL_DEPTH_TEST);
  if(c == 'd') glDisable(GL_DEPTH_TEST);
  if(c == 'C') glEnable(GL_CULL_FACE);
  if(c == 'c') glDisable(GL_CULL_FACE);
  if(c == 'B') glCullFace(GL_BACK);
  if(c == 'b') glCullFace(GL_FRONT);
  if(c == '0') glEnable(GL_LIGHT0);
  if(c == '=') glDisable(GL_LIGHT0);
  if(c == 'v') { if(++verzija > 3) verzija = 0; }
  if(c == 'N') { if(++nn > 50) nn = 50; }
  if(c == 'n') { if(--nn < 3) nn = 3; }
} // tipka

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

int main(int argc, char** argv) {
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB);

  glutInitWindowSize(640, 480);
  glutCreateWindow("stozac");

  glShadeModel(GL_FLAT);
  glClearColor(0.0, 0.0, 0.0, 0.0);

  glEnable(GL_LIGHTING);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHT0);

  glutDisplayFunc(slikaj);
  glutReshapeFunc(skaliraj);
  glutKeyboardFunc(tipka);
  glutIdleFunc(rotiraj);

  glutMainLoop();
  return 0;
} // main

