/*
 * Portions Copyright (c) 1993-1997, Silicon Graphics, Inc.
 * ALL RIGHTS RESERVED 
 */

/*
 *  helixfly.c
 *  This program demonstrates a single modeling transformation,
 *  glScalef() and a single viewing transformation, gluLookAt(),
 *  with mouse based rotation of the figure.
 *  A wireframe helix is rendered.
 */
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <GL/glut.h>
#include <math.h>
#define PI 3.14159


void drawHelix(float scale, float twists, float bends) {
/*pre: bends and twists != 0 */

   float x,y,z,t;

   glBegin(GL_LINE_STRIP);
       for (t = 0; t < twists; t += 1/bends) {
           x = scale* cos(2*PI*t);
           y = scale* sin(2*PI*t);
           z = scale* t/twists;
           glVertex3f(x,y,z);
           }
   glEnd();

   }


GLfloat light_diffuse[] = {1.0, 0.0, 0.0, 1.0};  /* Red diffuse light. */
GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0};  /* Infinite light location. */

GLfloat XAngle = 0;
GLfloat YAngle = 0;
GLfloat ZAngle = 0;

GLfloat t = 0.0;
GLfloat Deltat = 0.1;

GLfloat twists = 4, bends = 6;

   
void
stroke_output(GLfloat Scale, GLfloat x, GLfloat y, GLfloat z, char *format,...)
{
  va_list args;
  char buffer[200], *p;

  va_start(args, format);
  vsprintf(buffer, format, args);
  va_end(args);
  glPushMatrix();
  glTranslatef(x, y, z);
  glScalef(0.005*Scale, 0.005*Scale, 0.005*Scale);
  for (p = buffer; *p; p++)
    glutStrokeCharacter(GLUT_STROKE_ROMAN, *p);
  glPopMatrix();
}


void
drawAxes(void) 
{

  glDisable(GL_LIGHTING);
   glBegin(GL_LINES);
   glColor3f(1.0, 1.0, 1.0);
   glVertex3f(-2.0, 0.0, 0.0);
   glVertex3f( 2.0, 0.0, 0.0);
   glVertex3f( 0.0, -2.0, 0.0);
   glVertex3f( 0.0,  2.0, 0.0);
   glVertex3f( 0.0, 0.0, -2.0);
   glVertex3f( 0.0, 0.0, 2.0);
   glEnd();
   
   stroke_output(0.5, 2.0, 0.0, 0.0, "X");
   stroke_output(0.5, 0.0, 2.0, 0.0, "Y");
   stroke_output(0.5, 0.0, 0.0, 2.0, "Z");
}





void
display(void)
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    /* Adjust cube position to be asthetic angle. */
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt(0, 0, 5.0,  /* eye is at (0,0,5) */
    0.0, 0.0, 0.0,      /* center is at (0,0,0) */
    0.0, 1.0, 0.);      /* up is in positi_ve Y direction */
  glTranslatef(0.0, 0.0, -1.0);
  glRotatef(XAngle, 1.0, 0.0, 0.0);
  glRotatef(YAngle, 0.0, 1.0, 0.0);
  drawAxes();
  glColor3f(1.0, 0.0, 1.0);
  drawHelix(1.0, twists, bends);
  glutSwapBuffers();
}

void
init(void)
{

  
  /* Use depth buffering for hidden surface elimination. */
  glEnable(GL_DEPTH_TEST);

  /* Setup the _view of the cube. */
  glMatrixMode(GL_PROJECTION);
  gluPerspective( /* field of view in degree */ 40.0,
    /* aspect ratio */ 1.0,
    /* Z near */ 1.0, /* Z far */ 10.0);
  glMatrixMode(GL_MODELVIEW);
  gluLookAt(0.0, 0.0, 5.0,  /* eye is at (0,0,5) */
    0.0, 0.0, 0.0,      /* center is at (0,0,0) */
    0.0, 1.0, 0.);      /* up is in positi_ve Y direction */

  /* Adjust cube position to be asthetic angle. */
  glTranslatef(0.0, 0.0, -1.0);
  glRotatef(XAngle, 1.0, 0.0, 0.0);
  
  glEnable(GL_NORMALIZE);

}

void moveit(int x, int y) {

/* Set X and Y rotation angle to mouse position */
/* Not elegant, but it works */
  XAngle = x;
  YAngle = y;
  glutPostRedisplay();

}

void HaltRotate(int status, int x, int y) {

if (status == GLUT_MENU_IN_USE) 
   glutMotionFunc(NULL);
else
   glutMotionFunc(moveit);



}

void HandleMenu(int choice) {


   switch (choice) {
   
     case 1: twists ++; break;
     
     case 2: if (twists != 1) twists --; break;
     
     case 3: bends ++; break;
     
     case 4: if (bends != 1) bends --; break;
     
     }
     
     glutPostRedisplay();
 
  
  }
  
  
void initMenus(void) {

  glutCreateMenu(HandleMenu);
  glutAddMenuEntry("More twists", 1);
  glutAddMenuEntry("Fewer twists", 2);
  glutAddMenuEntry("More bends", 3);
  glutAddMenuEntry("Fewer bends", 4);
  glutAttachMenu(GLUT_RIGHT_BUTTON);
  
  }

int
main(int argc, char **argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutCreateWindow("helix");
  initMenus();
  glutMenuStatusFunc(HaltRotate);
  glutDisplayFunc(display);
  glutMotionFunc(moveit);
  init();
  glutMainLoop();
  return 0;         
}
