/* Puts up a fence around the barn. Demonstrates display lists and affine transforms. This program uses twGround and twSky to draw those objects. The sky has the fun property of being opaque only on the inside, so you can look through it into the scene, but you see it behind your objects. This is accomplished by using one-sided polygons (which is not the TW default). The coordinate system for this scene has y=0 as the ground, and the origin approximately in the center of the front edge, but see the bounding box for details. Written by Caroline Geiersbach and Scott D. Anderson scott.anderson@acm.org Summer 2003 Modified in Fall 2006 to put a picket on the ground. This clarifies the difference between the display list (which makes drawing a picket easier) and the use of multiple affine transformations without push/pop of the modelview matrix. */ #include #include #include /* A picket is, essentially, a barn with two horizontal rails. The rails are 2D quads, and this vertex array gives the vertices for the lower rail. */ twTriple rail [] = { {0,0,0}, {5,0,0}, {5,2,0}, {0,2,0} }; void drawRail () { glBegin(GL_QUADS); { glVertex3fv(rail[0]); glVertex3fv(rail[1]); glVertex3fv(rail[2]); glVertex3fv(rail[3]); } glEnd(); } /* Draws one picket. The picket is 5 wide, 10 high, and 2 deep, with the reference point at the lower left front of the picket. Rails stick out 0.5 to the left and are flat planes through the middle of the picket, with a width of 5 and a height of 2, with the bottom edge at heights 1 and 4. */ void drawPicket() { twTriple maroon = {0.5,0,0}; twTriple black = {0,0,0}; twTriple orange = {1,0.5,0}; glPushMatrix(); glScalef(4,10,2); // must scale to create 4*10*2 barn twSolidBarn(maroon, black, orange); glPopMatrix(); glPushMatrix(); twColorName(TW_OLIVE); glTranslatef(-0.5,1,-1); drawRail(); glTranslatef(0,3,0); drawRail(); glPopMatrix(); } // The following is an arbitrary numeric identifier for this display list. // Here, we use 100 just because it is clearly not a coordinate of a // vertex, a scale factor, or any other number in the program. */ const int PICKET = 100; void drawInit() { /* Create a call list for one picket of the fence. The first argument is our numeric constant. The second requests that the graphics pipeline just record this display list, but don't draw anything. */ glNewList(PICKET, GL_COMPILE); drawPicket(); glEndList(); } void display(void) { twDisplayInit(); twCamera(); // draw ground twColorName(TW_GREEN); twGround(); // draw sky twTriple lightSkyBlue = { 135.0/255.0, 206.0/255.0, 250.0/255.0 }; twColor(lightSkyBlue,0,0); twSky(); // draw a picket lying on the ground in the middle of the field. With // the exception of using CallList instead of something like // drawPicket(), this is the same an any drawing code. glPushMatrix(); glTranslatef(0,0,-40); glRotatef(30,0,1,0); glRotatef(-90,1,0,0); glTranslatef(0,0,2); glCallList(PICKET); glPopMatrix(); // draw front fence glPushMatrix(); glTranslatef(-40,0,0); for(int i=0;i<20;i++) { glCallList(PICKET); glTranslatef(5,0,0); } glPopMatrix(); // draw right side fence glPushMatrix(); glTranslatef(60,0,0); glRotatef(90,0,1,0); for(int i=0;i<25;i++) { glCallList(PICKET); glTranslatef(5,0,0); } glPopMatrix(); // draw left side fence glPushMatrix(); glTranslatef(-40,0,0); glRotatef(90,0,1,0); for(int i=0;i<17;i++) { glCallList(PICKET); glTranslatef(5,0,0); } glPopMatrix(); // draw barn glPushMatrix(); glTranslatef(-40,0,-125); glRotatef(-90,0,1,0); glScalef(40,35,50); twTriple teal = {0,0.5,0.5}; twTriple dark_blue = {0,0,0.5}; twTriple cyan = {0,1,1}; twSolidBarn(teal,dark_blue,cyan); glPopMatrix(); glFlush(); glutSwapBuffers(); // necessary for animation } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); twInitWindowSize(500,500); glutCreateWindow(argv[0]); drawInit(); glutDisplayFunc(display); // the real limits are is -40,60 and -125,5 twBoundingBox(-45,65,0,65,-130,5); glLineWidth(2); twMainInit(); glutMainLoop(); return 0; }