Go Back

// This program could be compared to my original Mandelbrot set
// program (basicwindow.cpp), but that would be like comparing
// Algebra I to Galois Theory (well, not quite). This is much more
// complicated, though, and the interface is explained throughout
// the code in my useful, overly-capitalized comments.

#include <iostream.h>
#include <GL/glut.h>

GLint width=540, height=420, winX=50, winY=50;
GLint mainWindow, imgWindow, rotWindow, TM_Window;
int rot = 0;
double xMin = -2.0, xMax = 2.0, yMin = -2.0, yMax = 2.0;

const double TOL = 1e-5;
int equal(double a, double b);

// MAIN WINDOW FUNCTIONS
void display();
void reshape(int w, int h);
void keyPress(unsigned char key, int x, int y);

// GRAPH WINDOW FUNCTIONS
void initImg();
void displayImg();
void mouseImg(int button, int state, int x, int y);

// ROTATE WINDOW FUNCTIONS
void displayRot();
void mouseRot(int button, int state, int x, int y);

// INFO WINDOW FUNCTIONS
void displayTM();

//**************************************************************************
//                             Main Function                              **
//**************************************************************************

int main(int argc, char* argv[])
{
  // INITIALIZE GL WINDOW
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
  glutInitWindowSize(width, height);
  glutInitWindowPosition(winX, winY);

  //INITIALIZE MAIN WINDOW
  mainWindow = glutCreateWindow("My First Fractal, Part II");
  glutDisplayFunc(display);
  glutReshapeFunc(reshape);
  glutKeyboardFunc(keyPress);

  // INITIALIZE GRAPH WINDOW
  imgWindow = glutCreateSubWindow(mainWindow, 10, 10, 400, 400);
  glutDisplayFunc(displayImg);
  glutMouseFunc(mouseImg);
  glutKeyboardFunc(keyPress);

  // INITIALIZE ROTATE WINDOW
  rotWindow = glutCreateSubWindow(mainWindow, 420, 10, 110, 20);
  glutDisplayFunc(displayRot);
  glutMouseFunc(mouseRot);
  glutKeyboardFunc(keyPress);

  // INITIALIZE INFO WINDOW
  TM_Window = glutCreateSubWindow(mainWindow, 420, 40, 110, 370);
  glutDisplayFunc(displayTM);
  glutKeyboardFunc(keyPress);

  // START!
  initImg();
  glutMainLoop();

  return 0;
}

//**************************************************************************
//                             Equal Function                             **
//**************************************************************************

int equal(double a, double b)
{
  // USE TOLERANCE TO DETERMINE EQUALITY OF DOUBLES
  if (a - b >= 0 && a - b < TOL) return 1;
  if (b - a >= 0 && b - a < TOL) return 1;
  return 0; 
}

//**************************************************************************
//                             Main Window                                **
//**************************************************************************


void display()
{
  glClearColor(0.0, 0.0, 0.0, 1.0);
  glClear(GL_COLOR_BUFFER_BIT);
}

void reshape(int w, int h)
{
  glutSetWindow(mainWindow);
  glutPositionWindow(winX, winY);
  glutReshapeWindow(width, height);

  // DON'T ALLOW RESIZING! BWA HA HA HA HA!!!!

  glutSetWindow(imgWindow);
  glutPositionWindow(10, 10);
  glutReshapeWindow(400, 400);

  glutSetWindow(rotWindow);
  glutPositionWindow(420, 10);
  glutReshapeWindow(110, 20);

  glutSetWindow(TM_Window);
  glutPositionWindow(420, 40);
  glutReshapeWindow(110, 370);

  // REDRAW EVERYTHING

  glFlush();
  glutPostRedisplay();
}

void keyPress(unsigned char key, int x, int y)
{
  // HANDLE ROTATE COMMAND FROM KEYBOARD

  if (key == 'r')
  {
    rot = (rot + 1) % 30;
    displayImg();
  }
  if (key == 'R')
  {
    rot = (rot + 29) % 30;
    displayImg();
  }
}

//**************************************************************************
//                             Image Window                               **
//**************************************************************************

void initImg()
{
  glutSetWindow(imgWindow);
  glClearColor(0.0, 0.0, 0.0, 1.0);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-2.0, 2.0, -2.0, 2.0, -1.0, 1.0);
}

void displayImg()
{
  glutSetWindow(imgWindow);
  glClearColor(1.0, 1.0, 1.0, 1.0);
  glClear(GL_COLOR_BUFFER_BIT);
  glLoadIdentity();
  glOrtho(xMin, xMax, yMin, yMax, -1.0, 1.0);

  int i, j, iz;
  double x, y, za, zb, x1, y1, x2, y2;

  // FIND NUMBER OF PIXELS TO MINIMIZE COMPUTATION
  double deltaX = (xMax-xMin)/800, deltaY = (yMax-yMin)/800;

  // CREATE COLOR PALETTE TO CONTROL SHADING

  double palette[6][3] =
  { {1.0, 0.0, 0.0}, {1.0, 0.5, 0.0}, {1.0, 1.0, 0.0},
    {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}, {1.0, 0.0 ,1.0} };

  double colors[31][3];
  colors[30][0] = colors[30][1] = colors[30][2] = 0.0;
  for (i = 0; i < 30; i++)
    for (j = 0; j < 3; j++)
      colors[i][j] = palette[int(i/6)][j] / double(i%6 + 1);

  // CALCULATE PIXEL COLORS BASED ON MANDELBROT ITERATIONS:
  // Z(n) = Z(n-1)^2 + Z(0)

  glBegin( GL_POINTS );

  for (x = xMin; x < xMax; x += deltaX)
    for (y = yMin; y < yMax; y += deltaY)
    {
      za = x;
      zb = y;
      x1 = x, y1 = y;

      for (iz = 0; iz < 30; iz++)
      {
	if (x1*x1 + y1*y1 > 4) break;
	x2 = x1*x1 - y1*y1 + za;
	y2 = 2 * x1 * y1 + zb;
	x1 = x2, y1 = y2;
      }

      // FIND COLOR AND ALLOW FOR COLOR ROTATION
      if (iz != 30) iz = (iz + rot) % 30;
      glColor3f(colors[iz][0], colors[iz][1], colors[iz][2]);
      glVertex3f(x, y, 0.0);
    }

  glEnd();
}

void mouseImg(int button, int state, int x, int y)
{
  if (state == GLUT_DOWN)
  {
    // CONVERT FROM PIXELS TO COORDINATES
    double xp = ((double(x)/400)*(xMax-xMin)) + xMin;
    double yp = ((double(400-y)/400)*(yMax-yMin)) + yMin;

    // FIND SCREEN WIDTH (IN COORDINATES)
    double xRad = (xMax-xMin)/2.0, yRad = (yMax-yMin)/2.0;

    // ZOOM IN ON LEFT-CLICK
    if (button == 0)
    {
      xRad /= 2.0; yRad /= 2.0;
      xMin = (xp - xRad);
      xMax = (xp + xRad);
      yMin = (yp - yRad);
      yMax = (yp + yRad);
    }

    // ZOOM OUT ON RIGHT CLICK UNLESS IT'S ALREADY
    // AT ORIGINAL SIZE (IF SO, RECENTER THE SET)
    else if (button == 2)
    {
      if (equal(xRad, 2.0) && equal(yRad, 2.0))
      {
        xMin = -2;
        xMax = 2;
        yMin = -2;
        yMax = 2;
      }
      else
      {
	xRad *= 2; yRad *= 2;
        xMin = xp - xRad;
        xMax = xp + xRad;
        yMin = yp - yRad;
        yMax = yp + yRad;
      }
    }

    // REDISPLAY IMAGE
    glFlush();
    glutPostRedisplay();
  }
}

//**************************************************************************
//                             Color Rotate Window                        **
//**************************************************************************

void displayRot()
{
  // DISPLAY TEXT "Rotate Colors <R>" IN ROTATE WINDOW

  glutSetWindow(rotWindow);
  char message[20] = "Rotate Colors <R>";
  int i;

  glClearColor(1.0, 1.0, 1.0, 1.0);
  glClear(GL_COLOR_BUFFER_BIT);
  glLoadIdentity();
  glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

  glColor3f(0, 0, 0);
  glRasterPos3f(-.65, -0.25, 0);
  for (i = 0; i < 17; i++)
    glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, message[i]);
}

void mouseRot(int button, int state, int x, int y)
{
  // CHANGE ROTATION INFO UPON CLICKING IN ROTATE WINDOW:
  // LEFT CLICK ROTATES FORWARD, RIGHT CLICK ROTATES BACKWARD.

  if (state == GLUT_DOWN)
  {
    if (button == 0) rot = (rot + 1) % 30;
    if (button == 2) rot = (rot + 29) % 30;
    glutPostRedisplay();
    displayImg();
  }
}

//**************************************************************************
//                             TildeMan Window                            **
//**************************************************************************

void displayTM()
{
  // DISPLAY INSTRUCTIONS AND INFORMATION
  // ALL ABOUT TildeMan (THAT'S ME!) AND HIS PROGRAM

  glutSetWindow(TM_Window);

  char *msg[20];
  msg[0] = "    My First Fractal";
  msg[1] = "              Part II";
  msg[2] = "";
  msg[3] = "------------";
  msg[4] = "";
  msg[5] = "     by Gary Sivek";
  msg[6] = "";
  msg[7] = "          Period 7";
  msg[8] = "";
  msg[9] = "------------";
  msg[10] = "";
  msg[11] = " Click the \"Rotate\"";
  msg[12] = " window or press";
  msg[13] = "   the <R> key to";
  msg[14] = "  rotate the palette";
  msg[15] = "for the Mandelbrot";
  msg[16] = "  Set fractal. Left-";
  msg[17] = " click to zoom in,";
  msg[18] = "and right click to";
  msg[19] = " zoom out. Enjoy!";

  int i, j;

  glClearColor(1.0, 1.0, 1.0, 1.0);
  glClear(GL_COLOR_BUFFER_BIT);
  glLoadIdentity();
  glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

  glColor3f(0, 0, 0);
  
  for (i = 0; i < 20; i++)
  {
    glRasterPos3f(-0.75, 0.9 - double(i)/15, 0.0);
    j = 0;
    while (msg[i][j] != 0)
      glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, msg[i][j++]);
  }  
}

My Supercomp front page.
This page was created by Gary Sivek for 7th Period Supercomp.