#include <GL/glut.h>
#include <iostream>
#include <cstdlib>

using namespace std;

enum buffer_type {SINGLE, DOUBLE} bufferstate = SINGLE;

double C = 1.0/4.0;
double XMIN=-2.1,XMAX=2.1, YMIN= -2.1, YMAX=2.1;
double c,x;

double f(double xx)
{
return xx*xx+c;
}

void drawcurveandaxis()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3d(.9,.9,.2);
glBegin(GL_LINES);
glVertex2d(XMIN,0);
glVertex2d(XMAX,0);
glVertex2d(0,YMIN);
glVertex2d(0,YMAX);
glColor3d(.9,.3,.3);
glVertex2d(XMIN,YMIN);
glVertex2d(XMAX,YMAX);
glEnd();

glColor3d(.9,.3,.9);
glBegin(GL_LINE_STRIP);
for(double ii=XMIN ; ii <= XMAX ; ii+= .05)
   {
   glVertex2d(ii,f(ii));
   }
glEnd();
glFlush();
}

void idle()
{
   // Print OpenGL errors, if there are any (for debugging)
   if (GLenum err = glGetError())
   {
      cerr << "OpenGL ERROR: " << gluErrorString(err) << endl;
   }
   
   glColor3d(1,1,1);
   glBegin(GL_LINE_STRIP);
   glVertex2d(x,f(x));
   x = f(x);
   glVertex2d(x,x);
   glVertex2d(x,f(x));
   glEnd();
   glFlush();
}

void display(void)
{
   glDrawBuffer(bufferstate == SINGLE ? GL_FRONT : GL_BACK);
   drawcurveandaxis();
   if (bufferstate == DOUBLE) glutSwapBuffers();
}

void zap()
{
c=C;
x=rand()/double(RAND_MAX); //randomly from 0 to 1;
display();
}

void init (void) 
{
   glClearColor(0.0, 0.0, 0.0, 0.0);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluOrtho2D(XMIN,XMAX,YMIN,YMAX);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   zap();
}

void keyboard(unsigned char dakey, int xpos, int ypos)
{
   switch(dakey)
      {
      case 27: exit(0); break; //ESC key
      case 'z': zap(); break;
      case 'c': c += .01; x=rand()/double(RAND_MAX); display(); break;
      case 'C': c -= .01; x=rand()/double(RAND_MAX); display(); break;
      case 'r': x=rand()/double(RAND_MAX); display(); break;
      case 'd': display(); break;
      }
}

void special(int x,int y,int z){keyboard(x,y,z);}

int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
   glutInitWindowSize (601, 601); 
   glutInitWindowPosition (100, 100);
   glutCreateWindow ("Simple Chaos");
   init();
   glutDisplayFunc(display);
   glutKeyboardFunc(keyboard);
   glutSpecialFunc(special);
   glutIdleFunc(idle);
   glutMainLoop();
   return 0;   /* ANSI C requires main to return int. */
}
