/* * Sierpinski's gasket in 3d using pyramids (and a different formula) * by Andrey Mirtchovski (aam396@mail.usask.ca) */ #include #include #include #include #include #define BOUNDS 1 typedef struct fract { int depth; float size; float trans[3]; /* the (x,y,z) translation for this cube */ float p1[3]; float p2[3]; float p3[3]; float p4[3]; struct fract *next; } fract; int spin_x, spin_y, spin_z; /* x-y rotation and zoom */ int h, w; /* height, width of window */ int old_x, old_y, move_z; int depth = 3; int i = 0; fract *f; /* each triple corresponds to a distinct edge of a cube */ float boundary[8][3] = { {-1, -1, -1}, {-1, 1, -1}, { 1, -1, -1}, { 1, 1, -1}, {-1, -1, 1}, {-1, 1, 1}, { 1, -1, 1}, { 1, 1, 1}, }; void init(); void drawboundary(fract *f) { /* draws a funny-looking cube of given size */ glBegin(GL_TRIANGLES); glColor3f(255, 0, 0); glVertex3fv(f->p1); glVertex3fv(f->p2); glColor3f(0, 0, 0); glVertex3fv(f->p3); glColor3f(255, 0, 0); glVertex3fv(f->p4); glVertex3fv(f->p1); glColor3f(0, 0, 0); glVertex3fv(f->p3); glColor3f(255, 0, 0); glVertex3fv(f->p2); glVertex3fv(f->p4); glColor3f(0, 0, 0); glVertex3fv(f->p3); glColor3f(255, 0, 0); glVertex3fv(f->p1); glVertex3fv(f->p4); glVertex3fv(f->p2); glEnd(); } fract *make_fract(int depth) { /* creates a queue/linked list of smaller and smaller fractals, for each * fractal at each depth, we create 8 children and put them in the 8 * different corners of the parent cube */ int i = 0, j = 0; float size; fract *f, *l; /* first and last of the fractal queue */ fract *tmp; f = (fract *)malloc(sizeof(fract)); /* init the parent cube for depth 0 */ f->size = 10; size = f->size; f->depth = 0; f->next = NULL; f->trans[0] = 0; f->trans[1] = 0; f->trans[2] = 0; f->p1[0] = -size; f->p1[1] = -size; f->p1[2] = size; f->p2[0] = size; f->p2[1] = -size; f->p2[2] = size; f->p3[0] = 0; f->p3[1] = size; f->p3[2] = 0; f->p4[0] = 0; f->p4[1] = -1.25*size; f->p4[2] = -1.25*size; l = f; /* create iteratively the fractal blocks */ while(++i <= depth) { while(f->depth < i) { tmp = f; /* create 4 smaller pyramids */ for(j = 1; j < 5; j++) { l->next = (fract *)malloc(sizeof(fract)); l = l->next; l->depth = i; l->size = f->size/2.0; size = l->size; l->p1[0] = -size; l->p1[1] = -size; l->p1[2] = size; l->p2[0] = size; l->p2[1] = -size; l->p2[2] = size; l->p3[0] = 0; l->p3[1] = size; l->p3[2] = 0; l->p4[0] = 0; l->p4[1] = -1.25*size; l->p4[2] = -1.25*size; l->next = NULL; switch (j) { case 1: l->trans[0] = f->p1[0]/2 + f->trans[0]; l->trans[1] = f->p1[1]/2 + f->trans[1]; l->trans[2] = f->p1[2]/2 + f->trans[2]; break; case 2: l->trans[0] = f->p2[0]/2 + f->trans[0]; l->trans[1] = f->p2[1]/2 + f->trans[1]; l->trans[2] = f->p2[2]/2 + f->trans[2]; break; case 3: l->trans[0] = f->p3[0]/2 + f->trans[0]; l->trans[1] = f->p3[1]/2 + f->trans[1]; l->trans[2] = f->p3[2]/2 + f->trans[2]; break; case 4: l->trans[0] = f->p4[0]/2 + f->trans[0]; l->trans[1] = f->p4[1]/2 + f->trans[1]; l->trans[2] = f->p4[2]/2 + f->trans[2]; break; } } f = f->next; /* should never be null!!! */ free(tmp); } } return f; } void free_fract(fract *f) { /* not used really, except for debugging */ fract *tmp; do { tmp = f; f = f->next; free(tmp); } while(f != NULL); } void reshape(int width, int height) { w = width; h = height; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 200.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity (); } void display(void) { int i; fract *tmp; GLfloat position[] = { -1.0, 1.0, 1.5, 0 }; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glLightfv (GL_LIGHT0, GL_AMBIENT, position); glPopMatrix(); glPushMatrix(); glTranslatef(0, 0, spin_z-5); glRotatef(spin_x, 0, 1, 0); glRotatef(spin_y, 1, 0, 0); tmp = f; do { glPushMatrix(); glTranslatef(tmp->trans[0], tmp->trans[1],tmp->trans[2]); drawboundary(tmp); /* draw the pyramid */ glPopMatrix(); } while(tmp->next != NULL && (tmp = tmp->next)); glPopMatrix(); glutSwapBuffers(); } void idle(void) { glutPostRedisplay(); } void bail(int code) { exit(code); } void mouse(int button, int state, int x, int y) { switch(button) { case 0: old_x = x - spin_x; old_y = y - spin_y; break; case 2: old_y = y - spin_z; move_z = (move_z ? 0 : 1); } glutPostRedisplay(); } void motion(x, y) { if(!move_z) { spin_x = x - old_x; spin_y = y - old_y; } else { spin_z = y - old_y; } glutPostRedisplay(); } void keyboard(unsigned char key, int x, int y) { static int old_x = 50; static int old_y = 50; static int old_width = 512; static int old_height = 512; switch (key) { case 27: bail(0); break; case ' ': init(); break; case 'w': glutPositionWindow(old_x, old_y); glutReshapeWindow(old_width, old_height); break; case 'f': if (glutGet(GLUT_WINDOW_WIDTH) < glutGet(GLUT_SCREEN_WIDTH)) { old_x = glutGet(GLUT_WINDOW_X); old_y = glutGet(GLUT_WINDOW_Y); old_width = glutGet(GLUT_WINDOW_WIDTH); old_height = glutGet(GLUT_WINDOW_HEIGHT); glutFullScreen(); } break; case '1': depth = 1; free_fract(f); init(); break; case '2': depth = 2; free_fract(f); init(); break; case '3': depth = 3; free_fract(f); init(); break; case '4': depth = 4; free_fract(f); init(); break; case '5': depth = 5; free_fract(f); init(); break; case '6': depth = 6; free_fract(f); init(); break; case '7': depth = 7; free_fract(f); init(); break; case '8': depth = 8; free_fract(f); init(); break; case '9': depth = 9; free_fract(f); init(); break; } } void init(void) { w = glutGet(GLUT_WINDOW_WIDTH); h = glutGet(GLUT_WINDOW_HEIGHT); // glEnable(GL_LIGHTING); // glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); f = make_fract(depth); } int main(int argc, char** argv) { int i; srand(time()); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowPosition(50, 50); glutInitWindowSize(512, 512); glutInit(&argc, argv); glutCreateWindow("Sierpinski's Gasket (Pyramid)"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutMotionFunc(motion); glEnable (GL_DEPTH_TEST); if(argc == 2) { if (strcmp(argv[1], "-h") == 0) { fprintf(stderr, "%s [depth]\n", argv[0]); exit(0); } sscanf(argv[1], "%d", &depth); } printf("sierpinski's fractals...\n"); printf("by andrey mirtchovski (aam396@mail.usask.ca)\n"); printf("\npress 1-9 for different recursion depths\n"); printf("move mouse for rotation/zoom\n"); init(); glutIdleFunc(idle); glutMainLoop(); return 0; }