//MAKEFILE # To use this Makefile, just type make. That's it. CC = gcc LDLIBS = -L /usr/X11R6/lib -lGL -lGLU -lglut -lXmu -lX11 -lXi -lm INCLUDE = -I /usr/X11R6/include -I /usr/X11R6/include/GL executable: $(CC) -g $(INCLUDE) -o $I koch_snowflake $I koch_snowflake.c $(LDLIBS) ------------------------------------------------------------------------- //koch_snowflake.c /************************************************************************ * This program produces a Koch Snowflake. A Koch Snowflake starts with * a triangle and then takes every line segment and changes it from ___ * to _/\_. This is done recursively to create a snowflake affect. * Number of recursions is set by user. ***********************************************************************/ #include #include #include #include #include #include #include /*type definitions*/ typedef GLfloat xyPoint[2]; typedef GLfloat color3f[3]; typedef GLfloat color4f[4]; /*globals*/ int iterations = 0; xyPoint startDisplay = {0.0,0.0};//location to start the display at xyPoint endDisplay = {0.0,0.0};//location to finish the display at /*Functions that set the basic GL related variables*/ void setWindowVals(xyPoint windowSize, xyPoint windowLoc, char * windowName); void initSystem(color4f color, color3f drawColor, xyPoint startDisplay, xyPoint endDisplay, float ptSize); /*Functions for calculating new points on the line segment*/ void getFirstNewPoint(xyPoint startPoint, xyPoint endPoint, xyPoint tempPoint); void getThirdNewPoint(xyPoint startPoint, xyPoint endPoint, xyPoint tempPoint); void getMiddleNewPoint(xyPoint firstPoint, xyPoint lastPoint, xyPoint midPoint); /*recursive function that calls calculating functions and draws points*/ void setPoints(xyPoint startPoint, xyPoint endPoint, int iterationsLeft); /*The callback functions*/ void display(); void keyboardReader(unsigned char key, int x, int y); void mouseReader(int button, int state, int x, int y); /*function for writing text strings to the screen*/ void textWriter(char * text); /*Function main(int argc, char **argv) * This function defines all the variables for window settings. * It then polls user for number of iterations, initializes program * and calls glutMainLoop*/ int main(int argc, char **argv) { color4f winBGColor = {0.0, 0.0, 0.0, 0.0};//window background color color3f drawColor = {1.0, 1.0, 1.0};//color we are drawing in xyPoint windowSize = {500, 500};//size of the window xyPoint windowLoc = {0, 0};//location on screen of the window float ptsize = 0.5;//the point size char * windowName = "Koch Snowflake";//name of the window /*set the display area*/ startDisplay[0] = 0.0; startDisplay[1] = 0.0; endDisplay[0] = 500.0; endDisplay[1] = 500.0; /*poll the user for the number of iterations*/ printf("\nInput number of iterations and hit Enter\n"); printf("Using numbers below zero wont work. Numbers above 13 take a long time\n"); scanf("%d", &iterations); /*initiate interaction with the local window system*/ glutInit(&argc, argv); /*initialize the window variables*/ setWindowVals(windowSize, windowLoc, windowName); /*initialize the system*/ initSystem(winBGColor, drawColor, startDisplay, endDisplay, ptsize); glutMainLoop(); } /*Function setPoints(xyPoint startPoint, xyPoint endPoint, int iterationsLeft) * This function is called recursively. It first checks to see if any more iterations * are needed. If so, it calculates the three additional points and calls itself again. * If no more iterations are needed, it just returns.*/ void setPoints(xyPoint startPoint, xyPoint endPoint, int iterationsLeft){ xyPoint tempFirstPoint = {0.0, 0.0};//first new point on the line segment xyPoint tempThirdPoint = {0.0, 0.0};//third new point, also on line segment xyPoint tempMidPoint = {0.0, 0.0};//second point, located off the segment /*every line segment has 5 points. the start, the end, and the three created here.*/ if (iterationsLeft != 0) { /*calculate and store the first point in tempFirstPoint*/ getFirstNewPoint(startPoint, endPoint, tempFirstPoint); /*calculate and store the last point in tempThirdPoint*/ getThirdNewPoint(startPoint, endPoint, tempThirdPoint); /*calculate and store the second point in tempMidPoint*/ getMiddleNewPoint(tempFirstPoint, tempThirdPoint, tempMidPoint); /*go through another iteration, once for each part of the current subset.*/ setPoints(startPoint, tempFirstPoint, iterationsLeft-1); glVertex2f(tempFirstPoint[0], tempFirstPoint[1]); setPoints(tempFirstPoint, tempMidPoint, iterationsLeft-1); glVertex2f(tempMidPoint[0], tempMidPoint[1]); setPoints(tempMidPoint, tempThirdPoint, iterationsLeft-1); glVertex2f(tempThirdPoint[0], tempThirdPoint[1]); setPoints(tempThirdPoint, endPoint, iterationsLeft-1); } } /*Function display() * This function handles the initial triangle config, sets aside memory for the array, * and draws the object. It also calls the recursive point generating * function for each of the triangle's sides.*/ void display(){ char buffer[3] = "\n\n\n";//buffer for int-to-ascii conversion /*set values for initial triangle*/ xyPoint startingPoint = {100.0,150.0};//bottom right point of triangle int triangleSideSize = 300;//length of side of equilateral /*points of the original triangle*/ xyPoint triPoint1 = {0.0, 0.0}; xyPoint triPoint2 = {0.0, 0.0}; xyPoint triPoint3 = {0.0, 0.0}; /*calculate the points of the triangle*/ triPoint1[0] = startingPoint[0]; triPoint1[1] = startingPoint[1]; triPoint2[0] = startingPoint[0] + triangleSideSize/2; triPoint2[1] = startingPoint[1] + triangleSideSize/2 * sqrt(3); triPoint3[0] = startingPoint[0] + triangleSideSize; triPoint3[1] = startingPoint[1]; /*clear the screen*/ glClear(GL_COLOR_BUFFER_BIT); /*start the openGL drawing loop for the polygon*/ glBegin(GL_LINE_LOOP); /*run the recursion once for each side*/ glVertex2f(triPoint1[0], triPoint1[1]); setPoints(triPoint1, triPoint2, iterations); glVertex2f(triPoint2[0], triPoint2[1]); setPoints(triPoint2, triPoint3, iterations); glVertex2f(triPoint3[0], triPoint3[1]); setPoints(triPoint3, triPoint1, iterations); glEnd(); /*set the position for the text*/ glRasterPos2i(startDisplay[0] + 10, endDisplay[1] - 13); /*output the text to screen*/ textWriter("Koch Snowflake with \n"); if (iterations < 10){ sprintf(buffer, "%d", iterations); buffer[1] = '\n'; } else{ sprintf(buffer, "%d", iterations); buffer[2] = '\n'; } textWriter(buffer); textWriter (" iterations.\n"); /*set position for next line*/ glRasterPos2i(startDisplay[0] + 10, endDisplay[1] - 26); textWriter ("Right click - Zoom Out. Left click - Zoom In.\n"); /*set position for next line*/ glRasterPos2i(startDisplay[0] + 10, startDisplay[1] + 20); textWriter ("Press C to change color\n"); /*set position for next line*/ glRasterPos2i(startDisplay[0] + 10, startDisplay[1] + 7); textWriter ("Press Q to quit\n"); /*send to screen*/ glFlush(); } /*Function mouseReader(int button, int state, int x, int y) * This is a very simple mouse reading function*/ void mouseReader(int button, int state, int x, int y){ /*left click, zoom in*/ if (state == GLUT_DOWN && button == GLUT_LEFT_BUTTON){ startDisplay[0] = startDisplay[0] + 10; startDisplay[1] = startDisplay[1] + 10; endDisplay[0] = endDisplay[0] - 10; endDisplay[1] = endDisplay[1] - 10; /*set new display information*/ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(startDisplay[0], endDisplay[0], startDisplay[1], endDisplay[1]); display(); } /*right click, zoom out*/ if (state == GLUT_DOWN && button == GLUT_RIGHT_BUTTON){ startDisplay[0] = startDisplay[0] - 10; startDisplay[1] = startDisplay[1] - 10; endDisplay[0] = endDisplay[0] + 10; endDisplay[1] = endDisplay[1] + 10; /*set new display information*/ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(startDisplay[0], endDisplay[0], startDisplay[1], endDisplay[1]); display(); } } /*Function keyboardReader(unsigned char key, int x, int y) * This is a very simple keyboard device reading function.*/ void keyboardReader(unsigned char key, int x, int y){ static int drawingColor = 0; if ((key == 'Q') || (key == 'q')){ exit(1); } if ((key == 'C') || (key == 'c')){ switch(drawingColor) { case 0: { glColor3f(1.0, 0.0, 0.0); drawingColor = 1; display(); break; } case 1: { glColor3f(0.0, 1.0, 0.0); drawingColor = 2; display(); break; } case 2: { glColor3f(0.0, 0.0, 1.0); drawingColor = 3; display(); break; } case 3: { glColor3f(0.0, 1.0, 1.0); drawingColor = 4; display(); break; } case 4: { glColor3f(1.0, 1.0, 0.0); drawingColor = 5; display(); break; } case 5: { glColor3f(1.0, 0.0, 1.0); drawingColor = 6; display(); break; } case 6: { glColor3f(1.0, 1.0, 1.0); drawingColor = 0; display(); break; } } } } /* Function initSystem(color4f winColor, color3f drawColor, xyPoint startDisp, xyPoint endDisp, float ptSize) * This function initializes all of display variables*/ void initSystem(color4f winColor, color3f drawColor, xyPoint startDisp, xyPoint endDisp, float ptSize){ /*set the background color*/ glClearColor(winColor[0], winColor[1], winColor[2], winColor[3]); /*clear the window*/ glClear(GL_COLOR_BUFFER_BIT); /*set the drawing color*/ glColor3f(drawColor[0], drawColor[1], drawColor[2]); glMatrixMode(GL_PROJECTION); glLoadIdentity(); /*set the portion of the world to display*/ gluOrtho2D(startDisp[0], endDisp[0], startDisp[1], endDisp[1]); glMatrixMode(GL_MODELVIEW); /*set the point size*/ glPointSize(ptSize); /*set the callback functions*/ glutDisplayFunc(display); glutKeyboardFunc(keyboardReader); glutMouseFunc(mouseReader); } /*Function setWindowVals(xyPoint size, xyPoint pos, char * name) * Set the variables for the window*/ void setWindowVals(xyPoint size, xyPoint pos, char * name){ /*set number and type of buffers*/ glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); /*set the window size*/ glutInitWindowSize(size[0], size[1]); /*position the window*/ glutInitWindowPosition(pos[0], pos[1]); /*actually create the window*/ glutCreateWindow(name); } /*Function getFirstNewPoint(xyPoint startPoint, xyPoint endPoint, xyPoint tempPoint) * calculate the first new point on the line segment*/ void getFirstNewPoint(xyPoint startPoint, xyPoint endPoint, xyPoint tempPoint){ /*calculate 1/3 of X distance*/ tempPoint[0] = startPoint[0] + (endPoint[0] - startPoint[0])/3; /*calculate 1/3 of Y distance*/ tempPoint[1] = startPoint[1] + (endPoint[1] - startPoint[1])/3; } /*Function getThirdNewPoint(xyPoint startPoint, xyPoint endPoint, xyPoint tempPoint) * calculate the third new point on the line segment.*/ void getThirdNewPoint(xyPoint startPoint, xyPoint endPoint, xyPoint tempPoint){ /*calculate 1/3 of X distance*/ tempPoint[0] = startPoint[0] + 2*(endPoint[0] - startPoint[0])/3; /*calculate 1/3 of Y distance*/ tempPoint[1] = startPoint[1] + 2*(endPoint[1] - startPoint[1])/3; } /*Function getMiddleNewPoint(xyPoint firstPoint, xyPoint lastPoint, xyPoint midPoint) * Calculates the second new point (The tip of the new triangle).*/ void getMiddleNewPoint(xyPoint firstPoint, xyPoint lastPoint, xyPoint midPoint){ double angle;//angle of incidence double hypot;//the length of the segment float segX;//the delta X of the middle line segment float segY;//the delta Y of the middle line segment float delX;//X distance from reference point to middle point we want float delY;//Y distance from reference point to middle point we want /*calculate the changes in X and Y axis*/ segX = lastPoint[0] - firstPoint[0]; segY = lastPoint[1] - firstPoint[1]; /*treating this like a triangle, we find the hypotenuse length*/ hypot = sqrt(segX * segX + segY * segY); /*calculate the angle for the hypotenuse*/ angle = atan(segY/segX); /*calculate the midpoint of the segment. * This is used as a reference point*/ midPoint[0] = firstPoint[0] + (segX)/2; midPoint[1] = firstPoint[1] + (segY)/2; /*Find the delta from reference point to final point*/ delX = hypot * sin(angle); delY = hypot * cos(angle); /*To be able to calcualte triangles that always point outward so that * we end up with a coherent polygon, we must always find a point that * is to the "left" of the line assuming that you are travelling from * the start to the end of a segment. Since the X and Y coordinates * of "left" change, dependent on the direction we are traveling, we * must have different cases*/ /*Moving up and right, or straight up*/ if ((segX >=0) && (segY > 0)){ midPoint[0] = midPoint[0] - delX; midPoint[1] = midPoint[1] + delY; } else{ /*Moving down and right, or straight right*/ if ((segX > 0) && (segY <= 0)){ midPoint[0] = midPoint[0] - delX; midPoint[1] = midPoint[1] + delY; } else{ /*Moving up and left, or straight left*/ if ((segX < 0) && (segY >= 0)){ midPoint[0] = midPoint[0] + delX; midPoint[1] = midPoint[1] - delY; }else{ /*Moving down and left, or straight down*/ if ((segX <= 0) && (segY < 0)){ midPoint[0] = midPoint[0] + delX; midPoint[1] = midPoint[1] - delY; } } } } } /*Function textWriter (char * text) * This function writes a null terminated character string to the screen*/ void textWriter (char * text){ int counter = 0; while ((char)text[counter] != '\n') { glutBitmapCharacter(GLUT_BITMAP_8_BY_13, text[counter]); counter++; } }