// sample problem discussed at the lecture 9/21/2004

#define GLUT_API_VERSION 4

#include <iostream>

#ifdef _WIN32
#include <windows.h>
#endif
#include <math.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#ifndef M_PI
#define M_PI            3.14159265358979323846
#endif 

#include "cvec2t.h"
#include "cvec3t.h"

typedef CVec2T<float> Vec2f;
typedef CVec3T<float> Vec3f;


namespace WindowParams {
  static int WindowWidth = 800;
  static int WindowHeight = 600;
  static int MainWindow; 
};

namespace Params { 
  const float WorldWidth = 15*1.33;
  const float WorldHeight = 15;
  const int TimerStep = 16; // millisec

  const Vec3f BackgroundColor(0.5,0.5,0.5);

};


void Reshape(int width, int height) {

  // glViewport defines part of the window we are going to use 
  WindowParams::WindowWidth = width;
  WindowParams::WindowHeight = height;
  glViewport(0,0,width,height);

  // initialize the viewing transformation (camera position) to identity; 
  // this corresponds to camera looking down negative z axis
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  // specify the projection transformation (camera parameters);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  // this defines a camera with orthogonal projection that captures the 
  // part of the virtual world inside the box from 
  // -WorldWidth/2 to WorldWidth/2 in the X direction 
  // -WorldHeight/2 to WorldHeight/2 in the Y direction 
  // and from 0 to 1 (default in Z direction 
  gluOrtho2D(-Params::WorldWidth/2, Params::WorldWidth/2,-Params::WorldHeight/2,Params::WorldHeight/2); 
}


void drawSquare(const Vec3f& color) { 
  glColor3fv(color);
  glRectfv( Vec2f(0,0), Vec2f(1,1));
}


const Vec3f red(1,0,0); 
const Vec3f blue(0,0,1); 
const Vec3f green(0,1,0); 
const Vec3f white(1,1,1);


void drawAxes() {  
  glLineWidth(3.0);
  glColor3fv(white);
  glBegin(GL_LINES); 
    glVertex2f(-5,0); 
    glVertex2f(5,0); 
    glVertex2f(0,-5); 
    glVertex2f(0,5); 
  glEnd();
}

float angle = 45;
float disp = 0; 

void Draw() {
  // set color to initialize the window to; the 4th component 
  // is the alpha value and is not used unless blending is enabled
  glClearColor( 0.5, 0.5,0.5,0.0);
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  glMatrixMode(GL_MODELVIEW);
  drawAxes();
  glPushMatrix();
    // this translation applies to both red and blue rectangles
    glTranslatef(disp,-3,0);
    glPushMatrix();
      // these scale applies only to the blue rectangle
      glScalef(3,1,1);  
      drawSquare(blue);
    glPopMatrix();
    glPushMatrix();
      // these transforms apply only to the red rectangle
      glTranslatef(3,0,0); 
      glRotatef(angle,0,0,1);
      glScalef(3,1,1);  
      drawSquare(red);
    glPopMatrix();

  glPopMatrix();
  // all drawing is done in the back buffer; 
  // the next function swaps the back and front buffer
  glutSwapBuffers();
}



void Animate(int time) {
  // timer callback needs to be reinstalled each time 
  angle += 1;
  disp += 0.1;
  glutTimerFunc(Params::TimerStep,Animate,0);
  glutPostRedisplay();
}



int main(int argc, char* argv[]) {

  // initialize glut and parse command-line aguments that glut understands
  glutInit(&argc, argv);

  // initialize dislay mode: 4 color components, double buffer and depth buffer
  glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);

  glutInitWindowSize(WindowParams::WindowWidth,WindowParams::WindowHeight);


  WindowParams::MainWindow = glutCreateWindow("Transforms");

  // register all callbacks

  // gets called whenever the window needs to be redrawn
  glutDisplayFunc(Draw); 
  // gets called whenever the window changes shape
  glutReshapeFunc(Reshape);

  // this insures that Animate is called the first time
  glutTimerFunc(Params::TimerStep,Animate,0);
  
  // this is an infinite loop get event - dispatch event which never returns
  glutMainLoop();
  return 0;
}











