/* This program displays a 2D surface looking vaguely like a coke bottle. The bottle silhouette is three Bezier curves, with the transitions at the upper bulge and lower dent, since I'll assume that the tangent is vertical at that point. Scott D. Anderson April 1999 Original Fall 2003 Revised to use TW */ #include /* ********************************************************************** Global variables, parameters and constants. */ /* Upper curve, from diameter of 0.75in at height 5in to diameter of 1.5in at height 2.5in. */ GLfloat upper_cp[4][3] = {{0.5/2, 5.0, 0.0}, {0.5/2, 4.0, 0.0}, {1.5/2, 3.0, 0.0}, {1.5/2, 2.5, 0.0}}; /* Middle curve, from upper bulge (see previous) to dent with diameter of 1.25in at height of 1.25in. */ GLfloat middle_cp[4][3] = {{1.5/2, 2.5, 0.0}, {1.5/2, 2.0, 0.0}, {1.25/2, 1.75, 0.0}, {1.25/2, 1.25, 0.0}}; /* Lower curve, from dent to base, with a radius the same as the bulge. */ GLfloat lower_cp[4][3] = {{1.25/2, 1.25, 0.0}, {1.25/2, 0.75, 0.0}, {1.5/2, 0.50, 0.0}, {1.5/2, 0.00, 0.0}}; // Control points for surfaces (quadrants of the bottle) GLfloat upperQ_cp[4][4][3]; GLfloat middleQ_cp[4][4][3]; GLfloat lowerQ_cp[4][4][3]; /* ================================================================ */ void draw_bezier_curve(GLfloat* cp) { int steps = 8; glMap1f(GL_MAP1_VERTEX_3, 0, 1, 3, 4, cp); glEnable(GL_MAP1_VERTEX_3); glMapGrid1f(steps,0.0,1.0); glEvalMesh1(GL_LINE,0,steps); } void draw_bezier_surface(GLfloat* cp) { int steps = 8; glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, cp); glEnable(GL_MAP2_VERTEX_3); glEnable(GL_AUTO_NORMAL); glMapGrid2f(steps,0.0,1.0,steps,0.0,1.0); glEvalMesh2(GL_FILL,0,steps,0,steps); } /* ================================================================ */ // The silhouette is a 1D curve; this rounds it out to a 2D surface with a // circular cross-section. void circular_slice(GLfloat surface_cp[4][4][3], GLfloat silhouette_cp[4][3]) { GLfloat radius, dist; int i,j; // i moves from one silhouette CP to another for(i=0; i<4; i++) { // j copies all the y values for these CPs, since they all have the same y for(j=0;j<4; j++) { surface_cp[i][j][1] = silhouette_cp[i][1]; } radius = silhouette_cp[i][0]; dist = radius*0.552; // distance of inner control points // circle CP0 is right on the silhouette, so x values are the same surface_cp[i][0][0] = radius; surface_cp[i][0][2] = 0.0; // CP1 is in front of the silhouette, at the same x, just 0.552 on the Z surface_cp[i][1][0] = radius; surface_cp[i][1][2] = dist; // CP2 is in front the silhouette, at the same Z as the CP3 surface_cp[i][2][0] = dist; surface_cp[i][2][2] = radius; // CP3 is at x=0, with Z being the X value of the silhouette CP surface_cp[i][3][0] = 0.0; surface_cp[i][3][2] = radius; } } /* ================================================================ */ void draw_silhouette() { int i; draw_bezier_curve(&upper_cp[0][0]); draw_bezier_curve(&middle_cp[0][0]); draw_bezier_curve(&lower_cp[0][0]); glPushMatrix(); glScalef(-1,1,1); draw_bezier_curve(&upper_cp[0][0]); draw_bezier_curve(&middle_cp[0][0]); draw_bezier_curve(&lower_cp[0][0]); glPopMatrix(); } // The silhouette is a 1D curve; this rounds it out to a 3D circular volume. void draw_circular_slice(GLfloat cp[4][4][3]) { int q=0; // q is the quadrant of the circular cross-section that we're drawing. glPushMatrix(); for(;;) { draw_bezier_surface(&cp[0][0][0]); if(q++>=4) break; glRotatef(90,0,1,0); } glPopMatrix(); } void draw_bottle() { draw_circular_slice(upperQ_cp); draw_circular_slice(middleQ_cp); draw_circular_slice(lowerQ_cp); } void set_lighting() { // Reddish light, in honor of Coke GLfloat light_ambient[] ={0.8, 0.4, 0.4, 1}; GLfloat light_diffuse[] ={0.8, 0.4, 0.4, 1}; GLfloat light_specular[]={1.0, 0.9, 0.9, 1}; GLfloat light_position[]={5, 5, 2, 1}; // to show the light location glPushMatrix(); glTranslatef(light_position[0],light_position[1],light_position[2]); twColorName(TW_YELLOW); glutSolidSphere(0.2,10,10); glPopMatrix(); // set up the light glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); // can't forget to do this! glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); } void display(void) { twDisplayInit(); twCamera(); glDisable(GL_LIGHTING); glPushMatrix(); glTranslatef(2,0,0); glLineWidth(2); twColorName(TW_CYAN); draw_silhouette(); glPopMatrix(); set_lighting(); glShadeModel(GL_SMOOTH); // smooth shading on the bottle twTriple bottleColor = {0.7, 0.7, 0.7}; twColor(bottleColor,1,20); draw_bottle(); glFlush(); glutSwapBuffers(); } int main(int argc, char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500,500); glutCreateWindow(argv[0]); glutDisplayFunc(display); twBoundingBox(-2,+5,0,5,-2,2); twMainInit(); circular_slice(upperQ_cp,upper_cp); circular_slice(middleQ_cp,middle_cp); circular_slice(lowerQ_cp,lower_cp); glutMainLoop(); }