                                                     
#include <math.h>
#include <stdlib.h>
#include "glaux.h"                         
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

const MAX = 100;                                            // Number of lines on each side 
double altitude[MAX][MAX],                                  // Array of heights for each vertex
        spin = 0.0,                                         // Amount of spin
        z = 0.0,                                            // Zoom Factor
        red = 1.0, green = 1.0, blue = 1.0;                 // RGB Components

void setAltitude() {                                 // Initializes heights
  int x, y;
  srand(123);
  for( x = 0; x < MAX; x++) 
    for( y = 0; y < MAX; y++)
      altitude[x][y]= (((double) x  -80.0)*(2* (double) -y+40.0)*((double) x -20)*((double)x+30)*( 1.5* (double) y -130))/10000000.00;
}

void pickColor(int x, int y ) {                      // Function to determine drawing color
  double temp;
  temp = altitude[x][y];
  green = temp / 5.0;
  red = fabs(temp) / 10.0;
  blue = 2.0 - temp / 20.0;
}

static void Init() {                                 // Initialization routine
  glClearColor(0.5, 0.5, 0.5, 0.0);
  glShadeModel(GL_FLAT);
}

static void Reshape(int width, int height) {         //  Determines Projection type
  glViewport(0, 0, GLint(width), GLint(height));
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(60.0, (GLfloat)width / (GLfloat)height, 1.0,  200.0);          // Perspective...
  glMatrixMode(GL_MODELVIEW);
}
                                                            // Defined Keys:
static void key_esc() { auxQuit(); }                        // Quit program

static void spinLeft() { spin -= 5; }                       // Rotate left 5 degrees

static void spinRight() { spin += 5; }                      // Rotate right 5 degrees

static void moveAway() { z += 5; }                           // Move object away 

static void moveCloser() { z -= 5; }                         // Move closervoid 

drawMyStuff() {// Basic Drawing Routine
  glLoadIdentity();                                                        // Identity Matrix     
  gluLookAt(0.0, MAX / 4.0, 2.0 * MAX, 0.0, 0.0, -10.0, 0.0, 1.0, 0.0);            // View Position
  glTranslatef(0.0, 0.0, MAX - z);                                         // Zoom Factor
  glRotatef(spin, 0.0, 1.0, 0.0);                                          // Rotate Factor
  for(int x=0;  x < MAX;  x++) {
    glBegin(GL_LINE_STRIP);                                 // Draw Segments in one direction
    for(int y = 0; y < MAX; y++) {
       pickColor(x,y);                                      // Change RGB Values
       glColor3f(red, green, blue);                         // Choose New Color
       glVertex3f(x - MAX / 2.0, altitude[x][y], y - MAX / 2.0);           // Draw segment
    }
    glEnd();
  }
  for(int y = 0; y < MAX; y++) {
    glBegin(GL_LINE_STRIP);                                 // Draw Segments in other direction
    for(int x = 0; x < MAX; x++) {
       pickColor(x,y);                                      // Change RGB Values
       glColor3f(red, green, blue);                         // Choose New Color
       glVertex3f(x - MAX / 2.0, altitude[x][y], y - MAX / 2.0);           // Draw segment

    }
    glEnd();
  }
}   

static void display() {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // Color and Depth
  glEnable(GL_DEPTH_TEST);
  
  drawMyStuff();
  glFlush();
  auxSwapBuffers();
}

void main() {
  setAltitude();                                            // Initialize heights
  auxInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);  // Initialize modes
  auxInitPosition(50, 50, 550, 550);
  if (auxInitWindow("3D Landscape")==GL_FALSE) auxQuit();
  Init();
  auxKeyFunc(AUX_LEFT, spinLeft);
  auxKeyFunc(AUX_RIGHT, spinRight);
  auxKeyFunc(AUX_UP, moveAway);
  auxKeyFunc(AUX_DOWN, moveCloser);
  auxExposeFunc(Reshape);
  auxReshapeFunc(Reshape);
  auxMainLoop(display);
}

