/***********************************************************************/
/*                                                                     */
/*  NAME     : Terry Fleury            PROGRAM : mp0                   */
/*  NET ID   : cs318ta1                COURSE  : CS318 - Fall 1999     */
/*  DUE DATE : September 10, 1998                                      */
/*  PURPOSE  : The purpose of this program is to introduce the class   */
/*             to the basics of OpenGL.  The program produces a        */
/*             spirograph using a certain number of line segments.     */
/*             The number of vertices can be an odd integer between    */
/*             3 and 99 (inclusive).  We also make the user input a    */
/*             "step size" to tell which vertices to connect.   A      */
/*             "step size" of 1 makes successive vertices connected,   */
/*             while a step size of 2 would skip vertices, making      */
/*             more of a star pattern.  The "step size" must be        */
/*             greater than 0 but less than the number of vertices.    */
/*  INPUT    : Two command line parameters (integers) to specify the   */
/*             number of line segments/vertices and step size to draw  */
/*             the spirograph.  For example, take the following input: */
/*                  mp0 5 2                                            */
/*             This would draw a standard star with 5 vertices,        */
/*             connecting every other vertex with a line segment.      */
/*             Type 'q' to quit.                                       */
/*                                                                     */
/***********************************************************************/

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

/*************************/
/*  FUNCTION PROTOTYPES  */
/*************************/
void Initialize(void);
void SetCameraPosition(void);
void UpdateDisplay(void);
void DrawSpirograph(void);
void KeyPressed(unsigned char,int,int);
void CheckParameters(int,char**);
void ReshapeWindow(int,int);
void QuitProgram(void);
void PrintHelp(void);

/**********************/
/*  GLOBAL CONSTANTS  */
/**********************/
const float TWOPI = 6.28318530718; 

/**********************/
/*  GLOBAL VARIABLES  */
/**********************/
int NumVertices;  /* Number of circle vertices - command line parameter */
int StepSize;     /* Which vertices to connect - command line parameter */

/***********************************************************************/
/*  Initialize is called at program invocation and sets up the main    */
/*  window.                                                            */
/***********************************************************************/

void Initialize(void)
{
  /* Initialize the window and color mode */
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
  glutInitWindowSize(600,600);
  glutCreateWindow("CS318 MP0 - Solution");

  glClearColor(0.0,0.0,0.0,0.0);   /* Background is black */
 
  SetCameraPosition();
}

/***********************************************************************/
/*  SetCameraPosition is called by several procedures to move the      */
/*  camera to the correct viewing position, and then sets GL_MODELVIEW */
/*  to allow drawing of objects on the screen.  For this MP, we view   */
/*  a 2D "circle" of radius 1 centered about the origin.               */
/***********************************************************************/

void SetCameraPosition(void)
{
  /* Set the viewing transformation */
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(-1.05,1.05,-1.05,1.05);
  glMatrixMode(GL_MODELVIEW);
}

/***********************************************************************/
/*  UpdateDisplay is called by the main event loop to refresh the      */
/*  contents of the display and to show the spirograph.                */
/***********************************************************************/

void UpdateDisplay(void)
{
  glClear(GL_COLOR_BUFFER_BIT);   /* Clear the main window */

  DrawSpirograph();    /* Do the actual drawing of the spirograph */

  glFlush();           /* Flush all output to the main window */
}

/***********************************************************************/
/*  DrawSpirograph is called by UpdateDisplay to draw the figure       */
/*  using the correct number of line segments and step size (stored in */
/*  the global variables NumVertices and StepSize).  The first vertex  */
/*  of the figure is located at (1,0), and subseqent vertices are      */
/*  located equidistant on a unit circle, proceeding counterclockwise. */
/***********************************************************************/

void DrawSpirograph(void)
{
  int vert = 0;   /* Counter for vertices around the figure */
  float rad;      /* Radians for position along unit circle */
  
  glColor3f(1.0,1.0,1.0);  /* Set the drawing color to white */
  
  /* Loop around the circle (which is 2*PI around) plotting */
  /* points at equidistant points along the unit circle.    */
  glBegin(GL_LINE_LOOP);
  while (vert != NumVertices)
    {
      rad = (float)vert * TWOPI / (float)NumVertices;
      glVertex2f(sin(rad),cos(rad));
      vert += StepSize;
      if (vert > NumVertices)
        vert -= NumVertices;
    }
  glEnd();
}

/***********************************************************************/
/*  ReshapeWindow is called if the main window needs to be resized.    */
/*  Note that this function is not really needed for this MP, but is   */
/*  given here for subsequent MPs.                                     */
/***********************************************************************/

void ReshapeWindow(int Width, int Height)
{
  SetCameraPosition();
  glViewport(0,0,Width,Height);
}

/***********************************************************************/
/*  QuitProgram is called to exit gracefully.                          */
/***********************************************************************/

void QuitProgram(void)
{
  exit(0);
}

/***********************************************************************/
/*  KeyPressed is called whenever a key is pressed by the user.  We    */
/*  check to see if the user hit 'q' or 'Q'.  If so, we quit.          */
/***********************************************************************/

void KeyPressed(unsigned char Key, int X, int Y)
{
  if (toupper(Key) == 'Q')
    QuitProgram();
}

/***********************************************************************/
/*  CheckParameters reads in the number of line segments specified on  */
/*  the command line and stores it in the global variable NumVertices. */
/*  The step size is stored in the global variable StepSize.  Then,    */
/*  we check to see if NumVertices is an odd integer between 3 and 99  */
/*  (inclusive), and StepSize is between 1 and (NumVertices-1)         */
/*  (inclusive).  If any of these conditions fail, we print out a      */
/*  "usage" message and quit.                                          */
/***********************************************************************/

void CheckParameters(int argc, char* argv[])
{
  if ((argc != 3) ||
      ((NumVertices = atoi(argv[1])) < 3) || (NumVertices > 99) ||
      ((NumVertices % 2) != 1) ||
      ((StepSize = atoi(argv[2])) < 1) || (StepSize >= NumVertices))
    {
      printf("Usage: mp0 <vertices> <stepsize>\n");
      printf("   <vertices> - The number of vertices for spirograph.\n");
      printf("                This number must be an odd integer between 3 and 99.\n");
      printf("   <stepsize> - Tells which vertices to connect with lines.\n");
      printf("                A 'stepsize' of 1 would connect consecutive points\n");
      printf("                to generate a 'circle'.\n");
      printf("                This number must be between 1 and (vertices-1).\n");
      QuitProgram();
    }
}

/***********************************************************************/
/*  PrintHelp is called at program startup to print out a short help   */
/*  message on how to use the program.                                 */
/***********************************************************************/

void PrintHelp(void)
{
  printf("CS318 - MP0 - OpenGL Introduction\n");
  printf("Type 'q' or 'Q' to Quit Program\n");
  fflush(NULL);   /* Make sure all output shows up */
}


/**************************/
/*   BEGIN MAIN PROGRAM   */
/**************************/

int main(int argc, char* argv[])
{
  glutInit(&argc,argv);
  
  /* Check to see if the user specified the number of vertices and step size */
  CheckParameters(argc,argv);

  PrintHelp();

  Initialize();    /* Set up main window and variables */
  
  /* Set the GLUT Callback Functions */
  glutKeyboardFunc(KeyPressed);
  glutReshapeFunc(ReshapeWindow);
  glutDisplayFunc(UpdateDisplay);
  glutMainLoop();
  
  return 0;    /* Required by ANSI C */
}

/**************************/
/*    END MAIN PROGRAM    */
/**************************/


