/**
 * Code by John Brosz for CPSC 453.  Taken and modified from my QT Designer tutorial.
 * Draws the Sierpinski Gasket and is a good start for assignment 1.
 */

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

// global variables
GLfloat xRot, yRot, zRot, scale;
GLuint object = 0;


struct Point {
	float x;
	float y;
}; // end Point

void drawSierpinski(Point a, Point b, Point c, int level);

// paint function, calls a display list to do its work.  Don't worry I'll cover these soon.
void paintGL()
{
  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();
  // set the zoom according to the scale variable
  glScalef(scale, scale, scale);
  // set the image rotation up according to xRot, yRot, zRot
  glRotatef( xRot, 1.0, 0.0, 0.0);
  glRotatef( yRot, 0.0, 1.0, 0.0);
  glRotatef( zRot, 0.0, 0.0, 1.0);

  glCallList(object);
  glFlush();
}

// creates a display list full of OpenGL commands that are executed whenever glCallList is called
GLuint makeObject()
{  
   GLuint list;
   list = glGenLists(1);
   glNewList(list, GL_COMPILE);
     // set the initial color
     glColor3f( 1.0, 0.0, 0.0 );
     // points for triangle to draw Sierpinski Gasket
     Point a, b, c;
     a.x=-0.5; a.y=-0.5;
     b.x=0.5; b.y=-0.5;
     c.x=0.0; c.y=0.5;
     drawSierpinski(a,b,c,3);
   glEndList();
   return list;
} // end make object

// some OpenGL initialization
void initializeGL()
{
  xRot = yRot = zRot = 0.0;
  scale = 1.25;
  glClearColor( 0.0, 0.0, 0.0, 0.0 ); // Let OpenGL clear to black
  glEnable( GL_DEPTH_TEST ); 
  object = makeObject(); // generate an OpenGL display list
  glShadeModel( GL_SMOOTH ); // we want smooth shading . . . try GL_FLAT if you like
}

void resizeGL( int w, int h )
{
  glViewport( 0, 0, (GLint)w, (GLint)h );
  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  glOrtho(-1.0,1.0,-1.0,1.0,-5.0,15.0);
  glMatrixMode( GL_MODELVIEW );
}


void keyPress(unsigned char key, int x, int y)
{
  switch (key) {
     case 27:
       glDeleteLists( object, 1 ); // clear our display list from memory
       exit(0); // exit normally
       break;
  } // end switch
}

void mouseMove(int x, int y)
{
   zRot += 1.0f;
   glutPostRedisplay();
}

//**********************************************************
// Draws a triangle
void drawTriangle(Point a, Point b, Point c)
{  glBegin(GL_TRIANGLES);
     glVertex2f(a.x,a.y);
     glVertex2f(b.x,b.y);
     glVertex2f(c.x,c.y);
   glEnd();
} // end draw triangle

//*******************************************************
// Function from class to draw the Sierpinski fractal
//   Recursion is FUN!
void drawSierpinski(Point a, Point b, Point c, int level)
{  
   Point m0, m1, m2;
   if (level > 0) {
     m0.x = (a.x+b.x) /2.0;
     m0.y = (a.y+b.y) /2.0;
     m1.x = (a.x+c.x) /2.0;
     m1.y = (a.y+c.y) /2.0;
     m2.x = (b.x+c.x) /2.0;
     m2.y = (c.y+b.y) /2.0;
     drawSierpinski(a,m0,m1,level-1);
     drawSierpinski(b,m2,m0,level-1);
     drawSierpinski(c,m1,m2,level-1);
   } else drawTriangle(a,b,c);
} // end draw Sierpinski

int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
   glutInitWindowSize(500, 500);
   glutCreateWindow(argv[0]); // this sets the window's title to the name of our executable file
   initializeGL();
   glutDisplayFunc(paintGL);
   glutReshapeFunc(resizeGL);
   glutMotionFunc(mouseMove);
   glutKeyboardFunc(keyPress);
   glutMainLoop();
   return 0;
}
   

