/*  This program generates an image of the bifurcation diagram in gray, and then 
    shows what each iteration looks like as a polynomial equation in terms of k.
    The iteration number is incremented by one each time the mouse is clicked,
    and the graph of the equation is drawn in red.   
*/

#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <GL/glut.h>

#define initial_width 700             // Initial Window Width 700 pixels
#define initial_height 350            // Initial Window Height 350 pixels

int main_window;          // Window ID number 
int iter = 1;		  // Keeps track of an iteration level
double x0;		  // Original X-value, entered from the keyboard
char s[30];		  // String variable for formatting printed text

// Draw text on the screen using pre-defined Bitmap character fonts 
// Passed arguments include location in 3-space, pointer to string, pointer to font

void bitmap_output(int x, int y, int z, char *string, void *font)
{  int len, i;
   glRasterPos3f(x, y, 0);            // Locate Raster Position in 3-space
   len = (int) strlen(string);        // Find length of string

   for (i = 0; i < len; i++) {        // Plot each characters in font style
       glutBitmapCharacter(font, string[i]);
    }
}


// Draws the Bifurcation Diagram - the first 50 iterations are not plotted.

DrawGraph()
{ double x, k, kstep;
  int i;
  kstep = 4.0/(initial_width-1);	    // Calculate distance between pixels
  glBegin(GL_POINTS);                       // Start drawing points
  glColor3f(0.8,0.8,0.8);                   // Set drawing color to gray 
  for (k=0; k< 4.0; k+= kstep)              // Step through k values
     { x = x0; 				    // Initialize 
      for( i=0; i<100; i++)		    // Calculate 100 iterations
       { x = k * x * (1.0 - x);		    // Logistic Difference Equation
         if (i>50) glVertex3f(k,x,0.0);     // Put a point at (k,x) after 50 iterations
       }
     }
  glEnd();
}

// Draw a set of labeled axes

//Draw some titles on the screen in available Times Roman fonts

void DrawTitles()
{ glColor3f(0.0, 0.0, 0.0);                  // Set color to Black
  glPushMatrix();                            // New frame of reference
  glTranslatef(0.1, 0.85, 0);                 // Move to new location
  sprintf(s,"Bifurcation");
  bitmap_output(0,0,0, s, GLUT_BITMAP_TIMES_ROMAN_24);  // Plot large title
  glPopMatrix();                             // Return to old reference
  glPushMatrix();                            // New frame of reference
  glTranslatef(0.1, 0.7, 0);                 // Move to new location
  sprintf(s,"Iteration %d", iter);
  bitmap_output(0,0,0, s, GLUT_BITMAP_TIMES_ROMAN_24);  // Plot large title
  glPopMatrix();                             // Return to old reference

} 

// Draw the resultant polynomial equation of the nth iteration
 
void DrawIter() 
{ double arr[initial_width];  	   // An array to hold iteration values for each k
  double k =0, x, kstep;
  int i, j;
  kstep=4.0/(initial_width -1);    // Determine how far apart k-values are
  for (i=0; i<initial_width; i++)
   { arr[i]=x0;			   // Initialize the array with x0
    }
  for (j=0; j<iter; j++)	   // Update array values for each iteration 
   { for (i=0; i<initial_width; i++)
       { x = arr[i];
         k = kstep * i;
         arr[i] = k * x * (1-x);
        }
    }
  glBegin(GL_LINE_STRIP);	   // Draw graph of polynomial in terms of k 
   glColor3f(1.0, 0.0, 0.0);
   for (i=0; i<initial_width; i++)
    {
     glVertex3f(kstep*i, arr[i], 0.0);
    }
  glEnd();
  glFlush();
} 

// Draw labeled axes on the screen.
void DrawAxes()
{int i=0;
 float k;
 glColor3f(0.0,0.0, 0.0);
 glBegin(GL_LINES);
 glVertex3f(-4.0, 0.0, 0.0);
 glVertex3f(4.0, 0.0, 0.0);
 glVertex3f( 0.0, -4.0, 0.0);
 glVertex3f(0.0, 4.0, 0.0);
 for (k = 0.0; k <4.0; k +=1.0)  // Make tic-marks along the axis. 
  {
   glVertex3f(k, 0.0, 0.0);
   glVertex3f(k, 0.05, 0.0);
  }
 glEnd();
 for (k = 0.0; k <4.0; k +=1.0)		// Label the axes with numbers
  {glPushMatrix();                    
    glTranslatef(k, -0.05, 0); 
    sprintf(s,"%d",i++);
    bitmap_output(0,0,0, s, GLUT_BITMAP_TIMES_ROMAN_10);  // Plot Number 
   glPopMatrix();             
  }
}

// Mouse Routine to increase the iteration number and redraw.

void mouse1(int button, int state, int x, int y)
{
  if (state == GLUT_DOWN){
      iter++;
      glFlush();             //  Force writing of GL commands
      glutPostRedisplay();   //  Cause the image to be redisplayed
     }
}

// Display window 

void display1(void)
{ glClear(GL_COLOR_BUFFER_BIT);               // Clear window area with proper color
  DrawGraph();
  DrawTitles();
  DrawAxes();
  DrawIter();
  glFlush();                                  // Force all drawing
}
                               

// 
void init(void) 	// Common Initialization stuff
{ /* select clearing (background) color   */
   glClearColor(1.0, 1.0, 0.8, 1.0);         

/* initialize viewing values */
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(0.0, 4.0, -1.0, 1.0, -1.0, 1.0);
}


int main(int argc, char **argv)
{
  printf("Enter initial x value:");
  scanf("%lf", &x0); 

  glutInit(&argc, argv);                      // Initialize with any passed arguments to main
  glutInitDisplayMode(GLUT_RGB);              // Initialize RGB mode in OpenGL
  glutInitWindowSize(initial_width, initial_height);  // Initialize window
  main_window = glutCreateWindow("Bifurcation ");  // Create main window with title
  init();
  glutDisplayFunc(display1);                  // Pass pointer to window display
  glutMouseFunc(mouse1);
  glutMainLoop();                             // Enter main loop - wait for events
  return 0;           
}
