// cutura - Hip - 2009-12-12
// iscrtava cuturu korishtenjem Bezierovih ploha

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

#define NKTY 9

int nn = 32; // broj poligona
double kutX = 0.0, kutY = 0.0;
float sivo[] = {0.6, 0.6, 0.6, 1.0};
float bijelo[] = {1.0, 1.0, 1.0, 1.0};
float tamnoSivo[] = {0.2, 0.2, 0.2, 0.2};

double oblik[NKTY][3] = {
  {0.5, 3.0, 0.0},
  {0.5, 2.0, 0.0},
  {0.5, 1.75, 0.0},
  {2.5, 1.5, 0.0},
  {2.5, 0.0, 0.0},
  {2.5, -1.0, 0.0},
  {2.5, -3.0, 0.0},
  {0.1, -3.0, 0.0},
  {0.0, -3.0, 0.0}
};

double ktocka[13][NKTY][3];

void izracunajKtocke() {
  int i, j, k;
  double krad, splj;

  for(j = 0; j < NKTY; j++) 
    for(k = 0; k < 3; k++) {
      ktocka[0][j][k] = oblik[j][k];
      ktocka[12][j][k] = oblik[j][k];
    }

  for(i = 0; i <= 4; i++) {
    krad = -i * M_PI / 4.0;
    for(j = 0; j < NKTY; j++) {
      if(j < 3) splj = 1.0; else splj = 0.5;
      ktocka[i + 1][j][0] = oblik[j][0] * cos(krad) - oblik[j][2] * sin(krad);
      ktocka[i + 1][j][1] = oblik[j][1];
      ktocka[i + 1][j][2] =
        splj * (oblik[j][0] * sin(krad) + oblik[j][2] * cos(krad))
        - 0.3 * oblik[j][0];
    }
  }

  // zrcaljenje prvih toccaka u zadnje
  for(i = 0; i < 6; i++)
    for(j = 0; j < NKTY; j++) {
      ktocka[6 + i][j][0] = -ktocka[i][j][0];
      ktocka[6 + i][j][1] =  ktocka[i][j][1];
      ktocka[6 + i][j][2] = -ktocka[i][j][2];
    }

} // izracunajKtocke

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_AMBIENT, tamnoSivo);
  glLightfv(GL_LIGHT0, GL_POSITION, pozicija);
} // svjetlo0

void iscrtaj(void) {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPushMatrix();
    glTranslated(-10.0, 0.0, 20.0);
    svjetlo0(); // postavi svjetlo
  glPopMatrix();

  glPushMatrix();
    glRotated(kutY, 0.0, 1.0, 0.0);
    glRotated(kutX, 1.0, 0.0, 0.0);

    // iscrtaj straznju plohu kao zhiccani okvir
    glMap2d(GL_MAP2_VERTEX_3, 0, 1, 3, NKTY,
      0, 1, NKTY * 3, 7, &ktocka[0][0][0]);
    glMapGrid2f(nn, 0.0, 1.0, nn, 0.0, 1.0);
    glEvalMesh2(GL_LINE, 0, nn, 0, nn);

    // iscrtaj prednju plohu pomochu poligona
    glMaterialfv(GL_FRONT, GL_DIFFUSE, sivo);
    glMaterialfv(GL_FRONT, GL_SPECULAR, bijelo);
    glMaterialf(GL_FRONT, GL_SHININESS, 100.0);

    glMap2d(GL_MAP2_VERTEX_3, 0, 1, 3, NKTY,
      0, 1, NKTY * 3, 7, &ktocka[6][0][0]);
    glMapGrid2f(nn, 0.0, 1.0, nn, 0.0, 1.0);
    glEvalMesh2(GL_FILL, 0, nn, 0, nn);
  glPopMatrix();

  glutSwapBuffers();
}

void skaliraj(int w, int h) {
  float a = 4.0, b;

  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  if(w > h) {
    b = a * (float)w / (float)h;
    glOrtho(-b, b, -a, a, -a, a);
  } else {
    b = a * (float)h / (float)w;
    glOrtho(-a, a, -b, b, -a, a);
  }

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
} // 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 == 'A') glEnable(GL_AUTO_NORMAL);
  if(c == 'a') glDisable(GL_AUTO_NORMAL);
  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 == 'N') { if(++nn > 50) nn = 50; }
  if(c == 'n') { if(--nn < 3) nn = 3; }
  glutPostRedisplay();
} // tipka

int mtipka, mstanje;

void mish(int tipka, int stanje, int x, int y)
{
  if(tipka == GLUT_MIDDLE_BUTTON) exit(0);

  mtipka = tipka;
  mstanje = stanje;
} // mish

void pomak(int x, int y) {
  int vp[4], vx, vy;

  if (mstanje == GLUT_UP) return;

  if(mtipka == GLUT_LEFT_BUTTON) {
    glGetIntegerv(GL_VIEWPORT, vp);
    vx = vp[2] * 0.5; vy = vp[3] * 0.5;
    kutY = 180.0 * (x - vx) / (float)vx;
    kutX = 180.0 * (y - vy) / (float)vy;
    glutPostRedisplay();
  }
} // pomak

int main(int argc, char **argv) {
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowSize(500, 500);
  glutInitWindowPosition(0, 0);
  glutCreateWindow(argv[0]);

  glClearColor(0.0, 0.0, 0.0, 0.0);
  glEnable(GL_DEPTH_TEST);

  izracunajKtocke();
  glEnable(GL_MAP2_VERTEX_3); // OBAVEZNO - inacce ne iscrtava!
  glEnable(GL_AUTO_NORMAL); // automatski raccuna normale

  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);

  glutReshapeFunc(skaliraj);
  glutDisplayFunc(iscrtaj);
  glutMotionFunc(pomak);
  glutMouseFunc(mish);
  glutKeyboardFunc(tipka);
  glutMainLoop();
  return 0;
} // main

