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++]);
}
}