/* Copyright (c) Mark J. Kilgard, 1994. */ /* This program is freely distributable without licensing fees and is provided without guarantee or warrantee expressed or implied. This program is -not- in the public domain. */ #include #include #include /* Uses EXT_polygon_offset extension if available to better render the fold outlines. */ #if GL_EXT_polygon_offset int polygon_offset; #endif enum { FLAT, /* completely flat sheet of paper */ FLAP1, /* left flap being folded in */ FLAP2, /* right flap being folded int */ CENTER2, /* right side folded up at center */ WING2, /* right wing folded down */ CENTER1, /* left side folded up at center */ WING1, /* left wing folded down */ FOLDED /* fully folded paper airplane */ } States; int motion = 1; int spinning = 1; int state = FLAT; int click = 0; int delay = 0; int direction; float flap1_angle = 0; float flap2_angle = 0; float center1_angle = 0; float center2_angle = 0; float wing1_angle = 0; float wing2_angle = 0; /** These correspond to the polygons for the paper sections: +----------+----------+ | /|\ | | 2 / | \ 3 | | / | \ | +------/ | \------+ | /| | |\ | | 1 / | | | \ 4 | | / | | | \ | | / | | | \ | | / | 5 | 6 | \ | |/ | | | \| + | | | + | 7 | | | 8 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +------+---+---+------+ */ typedef GLfloat Point[2]; Point poly1[] = { {-1, 0}, {-1 / 3.0, 2 / 3.0}, {-1, 2 / 3.0} }; Point poly2[] = { {-1, 1}, {-1, 2 / 3.0}, {-1 / 3.0, 2 / 3.0}, {0, 1} }; Point poly3[] = { {0, 1}, {1, 1}, {1, 2 / 3.0}, {1 / 3.0, 2 / 3.0} }; Point poly4[] = { {1 / 3.0, 2 / 3.0}, {1, 2 / 3.0}, {1, 0} }; Point poly5[] = { {-1 / 3.0, 2 / 3.0}, {0, 1}, {0, -1.5}, {-1 / 3.0, -1.5} }; Point poly6[] = { {0, 1}, {1 / 3.0, 2 / 3.0}, {1 / 3.0, -1.5}, {0, -1.5} }; Point poly7[] = { {-1, 0}, {-1 / 3.0, 2 / 3.0}, {-1 / 3.0, -1.5}, {-1, -1.5} }; Point poly8[] = { {1, 0}, {1 / 3.0, 2 / 3.0}, {1 / 3.0, -1.5}, {1, -1.5} }; void polydlist(int dlist, int num, Point points[]) { int i; glNewList(dlist, GL_COMPILE); glBegin(GL_POLYGON); for (i = 0; i < num; i++) { glVertex2fv(&points[i][0]); } glEnd(); glEndList(); } void idle(void) { if (spinning) click++; switch (state) { case FLAT: delay++; if (delay >= 80) { delay = 0; state = FLAP1; glutSetWindowTitle("origami (folding)"); direction = 1; } break; case FLAP1: flap1_angle += 2 * direction; if (flap1_angle >= 180) { state = FLAP2; } else if (flap1_angle <= 0) { state = FLAT; } break; case FLAP2: flap2_angle += 2 * direction; if (flap2_angle >= 180) { state = CENTER2; } else if (flap2_angle <= 0) { state = FLAP1; } break; case CENTER2: center2_angle += 2 * direction; if (center2_angle >= 84) { state = WING2; } else if (center2_angle <= 0) { state = FLAP2; } break; case WING2: wing2_angle += 2 * direction; if (wing2_angle >= 84) { state = CENTER1; } else if (wing2_angle <= 0) { state = CENTER2; } break; case CENTER1: center1_angle += 2 * direction; if (center1_angle >= 84) { state = WING1; } else if (center1_angle <= 0) { state = WING2; } break; case WING1: wing1_angle += 2 * direction; if (wing1_angle >= 84) { state = FOLDED; } else if (wing1_angle <= 0) { state = CENTER1; } break; case FOLDED: delay++; if (delay >= 80) { delay = 0; glutSetWindowTitle("origami (unfolding)"); direction = -1; state = WING1; } break; } glutPostRedisplay(); } void draw_folded_plane(void) { /* *INDENT-OFF* */ glPushMatrix(); glRotatef(click, 0, 0, 1); glRotatef(click / 5.0, 0, 1, 0); glTranslatef(0, .25, 0); glPushMatrix(); glRotatef(center1_angle, 0, 1, 0); glPushMatrix(); glTranslatef(-.5, .5, 0); glRotatef(flap1_angle, 1, 1, 0); glTranslatef(.5, -.5, 0); glCallList(2); glPopMatrix(); glCallList(5); glPushMatrix(); glTranslatef(-1 / 3.0, 0, 0); glRotatef(-wing1_angle, 0, 1, 0); glTranslatef(1 / 3.0, 0, 0); glCallList(7); glPushMatrix(); glTranslatef(-.5, .5, 0); glRotatef(flap1_angle, 1, 1, 0); glTranslatef(.5, -.5, 0); glCallList(1); glPopMatrix(); glPopMatrix(); glPopMatrix(); glPushMatrix(); glRotatef(-center2_angle, 0, 1, 0); glPushMatrix(); glTranslatef(.5, .5, 0); glRotatef(-flap2_angle, -1, 1, 0); glTranslatef(-.5, -.5, 0); glCallList(3); glPopMatrix(); glCallList(6); glPushMatrix(); glTranslatef(1 / 3.0, 0, 0); glRotatef(wing2_angle, 0, 1, 0); glTranslatef(-1 / 3.0, 0, 0); glCallList(8); glPushMatrix(); glTranslatef(.5, .5, 0); glRotatef(-flap2_angle, -1, 1, 0); glTranslatef(-.5, -.5, 0); glCallList(4); glPopMatrix(); glPopMatrix(); glPopMatrix(); glPopMatrix(); /* *INDENT-ON* */ } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glColor3ub(67, 205, 128); #if GL_EXT_polygon_offset if (polygon_offset) { glPolygonOffsetEXT(0.5, 0.0); glEnable(GL_POLYGON_OFFSET_EXT); } #endif draw_folded_plane(); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glColor3ub(255, 255, 255); #if GL_EXT_polygon_offset if (polygon_offset) { glPolygonOffsetEXT(0.0, 0.0); /* XXX a bug in the unpatched IRIX 5.3 OpenGL posts GL_INVALID_ENUM when GL_POLYGON_OFFSET_EXT is disabled; please ignore it. */ glDisable(GL_POLYGON_OFFSET_EXT); } else { glPushMatrix(); glTranslatef(0, 0, .05); } #else glPushMatrix(); glTranslatef(0, 0, .05); #endif draw_folded_plane(); #if GL_EXT_polygon_offset if (!polygon_offset) { glPopMatrix(); } #else glPopMatrix(); #endif glutSwapBuffers(); } void visible(int state) { if (state == GLUT_VISIBLE) { if (motion) glutIdleFunc(idle); } else { glutIdleFunc(NULL); } } void menu(int value) { switch (value) { case 1: direction = -direction; if (direction > 0) { glutSetWindowTitle("origami (folding)"); } else { glutSetWindowTitle("origami (unfolding)"); } break; case 2: motion = 1 - motion; if (motion) { glutIdleFunc(idle); } else { glutIdleFunc(NULL); } break; case 3: spinning = 1 - spinning; break; case 666: exit(0); } } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); glutCreateWindow("origami"); glutDisplayFunc(display); glutVisibilityFunc(visible); glClearColor(.488, .617, .75, 1.0); glMatrixMode(GL_PROJECTION); gluPerspective(40.0, 1.0, 0.1, 10.0); glMatrixMode(GL_MODELVIEW); gluLookAt(0, 0, 5.5, 0, 0, 0, 0, 1, 0); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glLineWidth(2.0); polydlist(1, sizeof(poly1) / sizeof(Point), poly1); polydlist(2, sizeof(poly2) / sizeof(Point), poly2); polydlist(3, sizeof(poly3) / sizeof(Point), poly3); polydlist(4, sizeof(poly4) / sizeof(Point), poly4); polydlist(5, sizeof(poly5) / sizeof(Point), poly5); polydlist(6, sizeof(poly6) / sizeof(Point), poly6); polydlist(7, sizeof(poly7) / sizeof(Point), poly7); polydlist(8, sizeof(poly8) / sizeof(Point), poly8); glutCreateMenu(menu); glutAddMenuEntry("Reverse direction", 1); glutAddMenuEntry("Toggle motion", 2); glutAddMenuEntry("Toggle spinning", 3); glutAddMenuEntry("Quit", 666); glutAttachMenu(GLUT_RIGHT_BUTTON); #if GL_EXT_polygon_offset polygon_offset = glutExtensionSupported("GL_EXT_polygon_offset"); #endif glutMainLoop(); return 0; /* ANSI C requires main to return int. */ }