/* Jin Ding -- Period 2 -- 3/17/98 */
/* torus.cpp */

#include <iostream.h>
#include "glaux.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <math.h>

#define MAX 100
#define HMAX MAX/2.0

double altitude[MAX][MAX],
  y=MAX/1.5,  // viewing height
  z=0.0,      // viewing distance
  red=1.0, green=1.0, blue=1.0,
  alt=10.0,   // height of hump
  spin=-90.0, // viewing angle
  cent=1.5;   // offset from center

double dist(int x,int y) {
double temp;

  temp=cent*MAX/10.0 - sqrt((x-HMAX)*(x-HMAX) + (y-HMAX)*(y-HMAX));
  return sqrt(temp*temp);
}

void setAltitude() {
int x,y;
double distance;

  for (x=0;x<MAX;x++)
    for (y=0;y<MAX;y++) {
      distance=dist(x,y);
      altitude[x][y]=(int)sqrt((alt*alt)-(distance*distance));
      if (distance > alt) altitude[x][y]=0.0;
    /* altitude ranges from 0 to alt */
    }
}

void pickColor(double value) {
  green=0.67-value/(3.0*alt/2.0);
  red=1.0-value/(4.0*alt/2.0);
  blue=0.0;
}

static void Init (void) {
  glClearColor(0.0,0.0,0.0,1.0);
  glShadeModel(GL_SMOOTH);
}

static void Reshape(int width, int height) {
  glViewport(0,0,(GLsizei)width,(GLsizei)height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(60.0,(GLfloat)width/(GLfloat)height,1.0,MAX*2.0);
  glMatrixMode(GL_MODELVIEW);
}

static void key_esc() { auxQuit(); }

static void moveUp() { y += 10; }

static void moveDown() { y -= 10; }

static void moveAway() { z += 5; }

static void moveCloser() { z -= 5; }

static void altNeg() { 
  if (alt > 1.0) {
    alt -= 1.0; 
    setAltitude(); 
  }
}
		
static void altPos() { alt += 1.0; setAltitude(); }

static void rippleIn() { 
  if (cent > 0) {
    cent -= .25; 
    setAltitude(); 
  }
}

static void rippleOut() { cent += .25; setAltitude(); }

static void spinR() { spin += 5.0; }

static void spinL() { spin -= 5.0; }

void DrawMyStuff() {
int x,y;
double distance;

  for (x=0;x<MAX-1;x++)
    for (y=0;y<MAX-1;y++) {
      if ((dist(x,y) <= alt) || (dist(x+1,y) <= alt) || (dist(x,y+1) <= alt) || (dist(x+1,y+1) <= alt)) {
        glBegin(GL_QUAD_STRIP);
        pickColor(altitude[x][y]);
        glColor3f(red,green,blue);
        glVertex3f(x-HMAX,-altitude[x][y],y-HMAX);
        pickColor(altitude[x+1][y]);
        glColor3f(red,green,blue);
        glVertex3f(x+1-HMAX,-altitude[x+1][y],y-HMAX);
        pickColor(altitude[x][y+1]);
        glColor3f(red,green,blue);
        glVertex3f(x-HMAX,-altitude[x][y+1],y+1-HMAX);
        pickColor(altitude[x+1][y+1]);
        glColor3f(red,green,blue);
        glVertex3f(x+1-HMAX,-altitude[x+1][y+1],y+1-HMAX);
        glEnd();
        glBegin(GL_QUAD_STRIP);
        pickColor(altitude[x][y]);
        glColor3f(red,green,blue);
        glVertex3f(x-HMAX,altitude[x][y],y-HMAX);
        pickColor(altitude[x+1][y]);
        glColor3f(red,green,blue);
        glVertex3f(x+1-HMAX,altitude[x+1][y],y-HMAX);
        pickColor(altitude[x][y+1]);
        glColor3f(red,green,blue);
        glVertex3f(x-HMAX,altitude[x][y+1],y+1-HMAX);
        pickColor(altitude[x+1][y+1]);
        glColor3f(red,green,blue);
        glVertex3f(x+1-HMAX,altitude[x+1][y+1],y+1-HMAX);
        glEnd(); 
      }
    }
}

static void display() {
  glClear(GL_COLOR_BUFFER_BIT);
  glPushMatrix();
    glLoadIdentity();
    gluLookAt(0.0,y,2.2*MAX,0.0,0.0,0.0,0.0,1.0,0.0);
    glTranslatef(0.0,0.0,MAX-z);
    glRotatef(spin,0.0,1.0,0.0);
    DrawMyStuff();
  glPopMatrix();
  glFlush();
  auxSwapBuffers();
}

void main() {
  setAltitude();
  auxInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  auxInitPosition(50,50,550,550);
  if (auxInitWindow("Torus") == GL_FALSE)
    auxQuit();
  Init();
  auxKeyFunc(AUX_LEFT,moveAway);
  auxKeyFunc(AUX_RIGHT,moveCloser);
  auxKeyFunc(AUX_UP,moveUp);
  auxKeyFunc(AUX_DOWN,moveDown);
  auxKeyFunc(AUX_i,altNeg);
  auxKeyFunc(AUX_k,altPos);
  auxKeyFunc(AUX_e,rippleIn);
  auxKeyFunc(AUX_d,rippleOut);
  auxKeyFunc(AUX_SPACE,spinR);
  auxKeyFunc(AUX_RETURN,spinL);
  cout<<"  left : moveAway        right : moveCloser\n"
      <<"    up : moveUp           down : moveDown\n"
      <<"     i : altNeg              k : altPos\n"
      <<"     e : rippleIn            d : rippleOut\n"
      <<" space : spinR          return : spinL\n";
  auxExposeFunc(Reshape);
  auxReshapeFunc(Reshape);
  auxMainLoop(display);
}
