/* mandlebrotgl.c   */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>      
#include <GL/glut.h>

static int width = 320;
static int height = 360; /* 40 for text */
static double center_x = 0.0;
static double center_y = 0.0;
static double size = 4.0;
static char message[] = "Click on new center. Type Q to stop, R to restart"; 
static int rgb[16][3] = {
  {000,000,000}, {255,000,000},  /* 0 black, 1 red */
  {255,255,000}, {000,255,255},  /* 2 magenta, 3 yellow */
  {000,255,000}, {000,000,255},  /* 4 green, 5 blue */
  {100,180,160}, {255,255,255},  /* 6 violet, 7 white */
  {240,180,000}, {255,000,255},  /* 8 orange, 9 cyan */
  {100,240,200}, {100,200,240},  /* 10 aquamarine, 11 turquoise */
  {255,200,200}, {100,255,255},  /* 12 pink, 13 goldenrod */
  {170,170,170}, {240,240,100}}; /* 14 grey, 15 sienna */
   
/* function prototypes */
static void printstring(float x, float y, char *string);
static void display(void);
static void myReshape(int w, int h);
static void myinit(void);
static void keyboard(unsigned char key, int x, int y);
static void special(int k, int x, int y);
static void mouse(int button, int state, int x, int y);
static void main_draw(void);
static int  pixelcolor(double c1, double c2);

static void printstring(float x, float y, char *string)
{
   int len, i;

   glRasterPos2f(x, y);
   len = (int) strlen(string);
   for (i = 0; i < len; i++)
      glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, string[i]);
} /* end printstring */

static void display(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  main_draw();
  glFlush();
} /* end display */

static void myReshape(int w, int h)
{
  width = w;
  height = h;
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(0.0,(GLfloat)w, 0.0, (GLfloat)h);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glClearColor (1.0, 1.0, 1.0, 0.0);  
} /* end myReshape */

void myinit(void)
{
  int i;
  
  glClearColor (1.0, 1.0, 1.0, 0.0);  
} /* end myinit */

static void keyboard(unsigned char key, int x, int y)
{
  switch (key)
  {
    case 'q':
      exit(0);
    case 'Q':
      exit(0);
    case 'r':
    case 'R':
      center_x = 0.0;
      center_y = 0.0;
      size = 4.0;
      break;
  }
  glutPostRedisplay();
} /* end keyboard */

static void special(int k, int x, int y)
{
  switch(k)
  {
    case GLUT_KEY_LEFT:
      
      break;
    case GLUT_KEY_RIGHT:
      
      break;
    case GLUT_KEY_DOWN:
      
      break;
    case GLUT_KEY_UP:
      
      break;
  }
  glutPostRedisplay();
} /* end special */

static void mouse(int button, int state, int x, int y)
{
  float center;
  double sizef;
  
  if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
  {
    printf("x=%d, y=%d \n", x, y);
    center = (float)width/2.0;
    center_x = center_x + (size/2.0) * (x - center)/center;
    center_y = center_y + (size/2.0) * (center - y + 40)/center;
    sizef =  4.0;
    size = size/sizef;
    printf("mouse center_x=%f, center_y=%f, size=%g \n",
            center_x, center_y, size);
    glutPostRedisplay();
  }
} /* end mouse */

static void main_draw(void)
{
  int color;
  int p1, p2;
  double x_0, y_0, dx, dy, x, y;
  char d_num_str[30];

  glClear(GL_COLOR_BUFFER_BIT);
  glLoadIdentity();

  glColor3f(0.0, 0.0, 0.0);
  printstring( 5, height-35, message);
  sprintf(d_num_str, "size= %e ", size);
  printstring( 5, height-25, d_num_str);
  sprintf(d_num_str, "x= %e ", center_x);
  printstring( 5, height-15, d_num_str);
  sprintf(d_num_str, "y= %e ", center_y);
  printstring( width/2, height-15, d_num_str);

  dx = size/(double)width;
  dy = size/(double)(height-40);
  x_0 = center_x - (size/2.0);
  y_0 = center_y - (size/2.0);

  printf("draw_main center_x=%f, center_y=%f, size=%g \n",
          center_x, center_y, size);
  printf("main_draw x_0=%f, y_0=%f, dx=%f, dy=%f \n",
          x_0, y_0, dx, dy);
          
  glPointSize(1.0);
  glBegin(GL_POINTS);
  x = x_0;
  for (p1=0; p1<=width; p1++)
  {
    y = y_0;
    for (p2=0; p2<=height-40; p2++)
    {
      color = pixelcolor(x, y);
      glColor3f(rgb[color][0]/255.0, rgb[color][1]/255.0, rgb[color][2]/255.0);
      glVertex3f((GLfloat)p1, (GLfloat)p2, 0.0);
      y = y + dy;
    }
    x = x + dx;
  }
  glEnd();  
} /* end of one main_draw */

/* generate pixel color */
static int pixelcolor(double c1, double c2)
{
  double z1, z2, sqrz1, sqrz2;
  static int color;

  z1 = 0.0;
  z2 = 0.0;
  sqrz1 = 0.0;
  sqrz2 = 0.0;
  for(color=0; color<=255; color++) /* 255 should be 255 but much slower*/
  {
    z2 = 2.0 * z1 * z2 + c2;
    z1 = sqrz1 - sqrz2 + c1;
    sqrz1 = z1 * z1;
    sqrz2 = z2 * z2;
    if ( (sqrz1 + sqrz2) > 4.0 ) return (color % 16);
  }
  return 0;
} /* end pixelcolor */

int main(int argc, char *argv[])
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB );
  glutInitWindowSize(width, height);
  glutCreateWindow(argv[0]);
  glutReshapeFunc(myReshape);
  glutMouseFunc(mouse);
  glutKeyboardFunc(keyboard);
  glutSpecialFunc(special);
  glutDisplayFunc(display);
  myinit();
  glutMainLoop();
  return 0;
} /* end main */
/* end mandelbrotgl.c */

