/* rings.c * * To compile: cc -o rings rings.c -lGL -lGLU -lX11 -lglut -lXmu -lm * * Usage: rings * * Homework 4, Part 1: perspective, hierarchical coords, moving eye pos. * * Do a slow zoom on a bunch of rings (ala Superman III?) * * Philip Winston - 2/21/95 * pwinston@hmc.edu * http://www.cs.hmc.edu/people/pwinston * */ #include #include #include #include /* Some files do not define M_PI... */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif typedef enum {MENU_STARTOVER, MENU_ZOOM_OUT, MENU_STOP_RINGS, MENU_STOP_FADE, MENU_START_RINGS, MENU_START_FADE, MENU_QUIT} MenuChoices; typedef enum {NOTALLOWED, CONE, TORUS, INNERMAT, OUTTERMAT} DisplayLists; #define STEPS 30 int Fade = 1; /* Start moving out */ float Axis = 0, AxisInc = (2.0 * M_PI / STEPS); GLfloat InnerRad, OutterRad, Tilt, Trans, TransCone, Dist; /* mainly computes the translation amount as a function of the tilt angle and torus radii */ void myInit(void) { float sinoftilt; InnerRad = 0.70; OutterRad = 5.0; Tilt = 15; Dist = 10; sinoftilt = sin(Tilt * M_PI*2/360); Trans = (2*OutterRad + InnerRad) * sinoftilt + InnerRad + ((1 - sinoftilt) * InnerRad) - (InnerRad * 1/10); TransCone = Trans + (OutterRad * sinoftilt + InnerRad); } /* I used code from the book's accnot.c as a starting point for lighting. I have one positional light in center, then one directional */ void myglInit(void) { GLfloat light0_position[] = { 1.0, 0.2, 1.0, 0.0 }; GLfloat light1_position[] = { 0.0, 0.0, 0.0, 1.0 }; GLfloat light1_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat light1_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat lm_ambient[] = { 0.2, 0.2, 0.2, 1.0 }; glEnable(GL_NORMALIZE); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glLightfv(GL_LIGHT0, GL_POSITION, light0_position); glLightfv(GL_LIGHT1, GL_POSITION, light1_position); glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse); glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular); glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.2); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lm_ambient); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); glFlush(); } void myreshape(GLsizei w, GLsizei h) { glViewport(0,0,w,h); glFlush(); } /* setup display lists to change material for inner/outter rings and to draw a single torus or cone */ void MakeDisplayLists(void) { GLfloat cone_diffuse[] = { 0.0, 0.7, 0.7, 1.0 }; GLfloat mat1_ambient[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat2_ambient[] = { 0.0, 0.0, 0.0, 0.0 }; GLfloat torus1_diffuse[] = { 0.7, 0.7, 0.0, 1.0 }; GLfloat torus2_diffuse[] = { 0.3, 0.0, 0.0, 1.0 }; GLfloat mat1_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat2_specular[] = { 0.5, 0.5, 0.5, 1.0 }; glNewList(INNERMAT, GL_COMPILE); glMaterialfv(GL_FRONT, GL_SPECULAR, mat1_specular); glMaterialf(GL_FRONT, GL_SHININESS, 50.0); glMaterialfv(GL_FRONT, GL_DIFFUSE, torus1_diffuse); glMaterialfv(GL_FRONT, GL_AMBIENT, mat1_ambient); glEndList(); glNewList(OUTTERMAT, GL_COMPILE); glMaterialfv(GL_FRONT, GL_SPECULAR, mat2_specular); glMaterialf(GL_FRONT, GL_SHININESS, 25.0); glMaterialfv(GL_FRONT, GL_DIFFUSE, torus2_diffuse); glMaterialfv(GL_FRONT, GL_AMBIENT, mat2_ambient); glEndList(); glNewList(CONE, GL_COMPILE); glMaterialfv(GL_FRONT, GL_DIFFUSE, cone_diffuse); glPushMatrix(); glTranslatef(0, -TransCone, 0); glRotatef(90, 1, 0, 0); glutSolidCone(OutterRad, 10, 8, 8); glPopMatrix(); glEndList(); glNewList(TORUS, GL_COMPILE); glPushMatrix(); glRotatef(90, 1, 0, 0); glutSolidTorus(InnerRad, OutterRad, 15, 25); glPopMatrix(); glEndList(); } /* Draw three rings, rotated and translate so they look cool */ void DrawRings(float axis) { GLfloat x = sin(axis), y = cos(axis); glPushMatrix(); glTranslatef(0, Trans, 0); glRotatef(Tilt, x, 0, y); glCallList(TORUS); glPopMatrix(); glPushMatrix(); glRotatef(-Tilt, x, 0, y); glCallList(TORUS); glPopMatrix(); glPushMatrix(); glTranslatef(0, -Trans, 0); glRotatef(Tilt, x, 0, y); glCallList(TORUS); glPopMatrix(); } /* Draw the inner thing, then glScale and draw 3 huge rings */ void mydisplay(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1, 1, -1, 1, 10, 1000); gluLookAt(0, 0, Dist, 0, 0, 0, 0, 1, 0); glMatrixMode(GL_MODELVIEW); glCallList(INNERMAT); DrawRings(Axis); glCallList(CONE); glCallList(OUTTERMAT); glPushMatrix(); glScalef(10, 10, 10); DrawRings(Axis/3); glPopMatrix(); glutSwapBuffers(); glFlush(); } /* rotate the axis and adjust position if nec. */ void myidle(void) { Axis += AxisInc; if (Dist < 15 && Fade) /* start slow */ Dist += 0.1; else if (Dist < 800 && Fade) /* don't go back too far */ Dist *= 1.005; mydisplay(); } /* nothing fancy */ void handlemenu(int value) { switch (value) { case MENU_STARTOVER: Dist = 10; Axis = 0; Fade = 1; AxisInc = (2.0 * M_PI / STEPS); glutChangeToMenuEntry(3, "Stop rings", MENU_STOP_RINGS); glutChangeToMenuEntry(4, "Stop fade", MENU_STOP_FADE); break; case MENU_ZOOM_OUT: Dist = 800; break; case MENU_STOP_RINGS: AxisInc = 0; glutChangeToMenuEntry(3, "Start rings", MENU_START_RINGS); break; case MENU_START_RINGS: AxisInc = (2.0 * M_PI / STEPS); glutChangeToMenuEntry(3, "Stop rings", MENU_STOP_RINGS); break; case MENU_STOP_FADE: Fade = 0; glutChangeToMenuEntry(4, "Start fade", MENU_START_FADE); break; case MENU_START_FADE: Fade = 1; glutChangeToMenuEntry(4, "Stop fade", MENU_STOP_FADE); break; case MENU_QUIT: exit(0); break; } } void MenuInit(void) { glutCreateMenu(handlemenu); glutAddMenuEntry("Start Over", MENU_STARTOVER); glutAddMenuEntry("Zoom Out", MENU_ZOOM_OUT); glutAddMenuEntry("Stop rings", MENU_STOP_RINGS); glutAddMenuEntry("Stop fade", MENU_STOP_FADE); glutAddMenuEntry("Quit", MENU_QUIT); glutAttachMenu(GLUT_RIGHT_BUTTON); } void vis(int visible) { if (visible == GLUT_VISIBLE) { glutIdleFunc(myidle); } else { glutIdleFunc(NULL); } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitWindowSize(512, 512); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutCreateWindow("rings"); myInit(); myglInit(); MakeDisplayLists(); MenuInit(); glutReshapeFunc(myreshape); glutDisplayFunc(mydisplay); glutVisibilityFunc(vis); glutMainLoop(); return 0; /* ANSI C requires main to return int. */ }