/* Definitions of new tw objects */ /* Vertex array for a unit twBarn (dimensions 1*1*1) */ // Should the following be a parameter of twDrawBarn, instead? const GLfloat BarnShoulderHeight = 0.7; twTriple twBarn[10] = { {0,0,0}, // 0, left, bottom, front {1,0,0}, // 1, right, bottom, front {1,BarnShoulderHeight,0}, // 2, right front shoulder {0.5,1,0}, // 3, ridge, front {0,BarnShoulderHeight,0}, // 4, left front shoulder {0,0,-1}, // 5, echo of 0 {1,0,-1}, // 6, echo of 1 {1,BarnShoulderHeight,-1}, // 7, echo of 2 {0.5,1,-1}, // 8, echo of 3 {0,BarnShoulderHeight,-1}, // 9, echo of 4 }; void twSolidBarn(twTriple endColor, twTriple sideColor, twTriple roofColor, GLfloat specular, GLfloat shininess) { twColor(endColor,specular,shininess); glNormal3f(0,0,1); glBegin(GL_POLYGON); // front { glVertex3fv(twBarn[0]); glVertex3fv(twBarn[1]); glVertex3fv(twBarn[2]); glVertex3fv(twBarn[3]); glVertex3fv(twBarn[4]); } glEnd(); glNormal3f(0,0,-1); glBegin(GL_POLYGON); // back { glVertex3fv(twBarn[5]); glVertex3fv(twBarn[9]); glVertex3fv(twBarn[8]); glVertex3fv(twBarn[7]); glVertex3fv(twBarn[6]); } glEnd(); twColor(sideColor,specular,shininess); glNormal3f(-1,0,0); glBegin(GL_POLYGON); // left side { glVertex3fv(twBarn[0]); glVertex3fv(twBarn[4]); glVertex3fv(twBarn[9]); glVertex3fv(twBarn[5]); } glEnd(); glNormal3f(1,0,0); glBegin(GL_POLYGON); // right side { glVertex3fv(twBarn[1]); glVertex3fv(twBarn[6]); glVertex3fv(twBarn[7]); glVertex3fv(twBarn[2]); } glEnd(); twColor(roofColor,specular,shininess); // These perpendicular vectors aren't normalized. // I'm using the perp idea as found in Hill's graphics book glNormal3f(BarnShoulderHeight-1,0.5,0); glBegin(GL_POLYGON); // left side roof { glVertex3fv(twBarn[4]); glVertex3fv(twBarn[3]); glVertex3fv(twBarn[8]); glVertex3fv(twBarn[9]); } glEnd(); glNormal3f(1-BarnShoulderHeight,0.5,0); glBegin(GL_POLYGON); // right side roof { glVertex3fv(twBarn[2]); glVertex3fv(twBarn[7]); glVertex3fv(twBarn[8]); glVertex3fv(twBarn[3]); } glEnd(); } void twWireBarn(twTriple xColor, twTriple yColor, twTriple zColor) { twColor(xColor,0,0); glBegin(GL_LINES); { // front horizontals glVertex3fv(twBarn[0]); glVertex3fv(twBarn[1]); glVertex3fv(twBarn[2]); glVertex3fv(twBarn[3]); glVertex3fv(twBarn[2]); glVertex3fv(twBarn[4]); glVertex3fv(twBarn[3]); glVertex3fv(twBarn[4]); // back horizonals glVertex3fv(twBarn[0+5]); glVertex3fv(twBarn[1+5]); glVertex3fv(twBarn[2+5]); glVertex3fv(twBarn[3+5]); glVertex3fv(twBarn[2+5]); glVertex3fv(twBarn[4+5]); glVertex3fv(twBarn[3+5]); glVertex3fv(twBarn[4+5]); } glEnd(); twColor(yColor,0,0); glBegin(GL_LINES); { // front glVertex3fv(twBarn[0]); glVertex3fv(twBarn[4]); glVertex3fv(twBarn[1]); glVertex3fv(twBarn[2]); // back glVertex3fv(twBarn[0+5]); glVertex3fv(twBarn[4+5]); glVertex3fv(twBarn[1+5]); glVertex3fv(twBarn[2+5]); } glEnd(); twColor(zColor,0,0); glBegin(GL_LINES); { glVertex3fv(twBarn[0]); glVertex3fv(twBarn[0+5]); glVertex3fv(twBarn[1]); glVertex3fv(twBarn[1+5]); glVertex3fv(twBarn[2]); glVertex3fv(twBarn[2+5]); glVertex3fv(twBarn[3]); glVertex3fv(twBarn[3+5]); glVertex3fv(twBarn[4]); glVertex3fv(twBarn[4+5]); } glEnd(); } /* It isn't particularly efficient to allocate some memory just to use it and discard it. It would be cleaner to allocate the memory once for each disk at the beginning of the program, and use the quadrics during the display function, but that's more awkward to code. The following function trades efficiency for convenience. */ void twDisk(GLfloat radius, GLint slices) { GLUquadric* tmpquad; tmpquad = gluNewQuadric(); if( tmpquad == 0 ) { printf("Can't allocate another quadric\n"); } else { gluQuadricDrawStyle(tmpquad,GL_POLYGON); gluDisk(tmpquad,0,radius,slices,1); gluDeleteQuadric(tmpquad); } } /* Similar efficiency comments as for twDisk. */ void twCylinder(GLfloat base, GLfloat top, GLfloat height, GLint slices, GLint stacks) { GLUquadric* myCylinder; myCylinder = gluNewQuadric(); if( myCylinder == 0 ) { printf("Can't allocate another quadric\n"); } else { gluQuadricDrawStyle(myCylinder,GL_POLYGON); gluQuadricNormals(myCylinder,GL_SMOOTH); gluCylinder(myCylinder,base,top,height,slices,stacks); gluDeleteQuadric(myCylinder); } } void twTube(GLfloat base, GLfloat top, GLfloat height, GLint slices,GLint stacks) { glPushMatrix(); // must flip sides so we see the correct side for shading glRotatef(180,1,0,0); twDisk(base,slices); glPopMatrix(); twCylinder(base,top,height,slices,stacks); // translate length of cylinder to draw bottom glPushMatrix(); glTranslatef(0,0,height); twDisk(top,slices); glPopMatrix(); } void twSolidCylinder(GLfloat top,GLfloat base,GLfloat height, GLint slices,GLint stacks) { glPushMatrix(); glRotatef(90,1,0,0); glPushMatrix(); // must flip sides so we see the correct side for shading glRotatef(180,1,0,0); twDisk(top,slices); glPopMatrix(); twCylinder(top,base,height,slices,stacks); // translate length of cylinder to draw bottom glTranslatef(0,0,height); twDisk(base,slices); glPopMatrix(); } /* Draws a bear within a 1*1*1 box, with the y axis running through the center. */ void twTeddyBear() { twTriple lightBrown = {0.8,0.5,0.3}; twTriple darkBrown = {0.7,0.4,0.2}; twTriple black = {0.0,0.0,0.0}; glPushMatrix(); twColor(lightBrown,0,0); glScalef(0.1,0.1,0.1); glTranslated(0,3,0); glPushMatrix(); glTranslated(-0.6,0.7,0.2); glScaled(1,1,0.5); glutSolidSphere(0.4,20,20); // left ear glPopMatrix(); glPushMatrix(); glTranslated(0.6,0.7,0.2); glScaled(1,1,0.5); glutSolidSphere(0.4,20,20); // right ear glPopMatrix(); // draw head, slightly darker brown twColor(darkBrown,0,0); // dark brown glPushMatrix(); glutSolidSphere(1,30,30); glTranslated(-0.25,0.1,0.9); twColor(black,1,64); // shiny black glutSolidSphere(0.12,20,20); // left eye glTranslated(0.5,0,0); glutSolidSphere(0.12,20,20); // right eye glTranslated(-0.25,-0.4,0); glutSolidSphere(0.2,10,10); // nose glPopMatrix(); // draw body twColor(lightBrown,0,0); // light brown again glTranslated(0,-3.8,0); glPushMatrix(); glScaled(1.3,2,1); glutSolidSphere(1.5,30,30); // body glPopMatrix(); // legs and arms are in darker brown twColor(darkBrown,0,0); // dark brown // draw right leg glTranslated(0.9,-1.9,0); glPushMatrix(); glRotated(35,-1,0,1); twSolidCylinder(0.7,0.6,2,20,1); glPopMatrix(); // draw left leg glTranslated(-1.8,0,0); glPushMatrix(); glRotated(-35,1,0,1); twSolidCylinder(0.7,0.6,2,20,1); glPopMatrix(); // draw left arm glTranslated(0,3.8,0); glPushMatrix(); glRotated(-90,0,0,1); twSolidCylinder(0.5,0.4,2,20,1); glPopMatrix(); // draw right arm glTranslated(2,0,0); glPushMatrix(); glRotated(90,0,0,1); twSolidCylinder(0.5,0.4,2,20,1); glPopMatrix(); glPopMatrix(); } void twGround(){ glPushAttrib(GL_POLYGON_BIT); glEnable(GL_CULL_FACE); glBegin(GL_QUADS); // y=BBMin[1]. The other coordinates change in the usual way. The // order is important, because we want the polygon to be facing the // center, so that it's culled when we look up at it, but not when we // look down on it. glVertex3f(BBMin[0],BBMin[1],BBMax[2]); glVertex3f(BBMax[0],BBMin[1],BBMax[2]); glVertex3f(BBMax[0],BBMin[1],BBMin[2]); glVertex3f(BBMin[0],BBMin[1],BBMin[2]); glEnd(); glPopAttrib(); } void twSky() { glPushAttrib(GL_POLYGON_BIT); glEnable(GL_CULL_FACE); glBegin(GL_QUADS); // y=BBMax[1] glVertex3f(BBMin[0],BBMax[1],BBMax[2]); glVertex3f(BBMin[0],BBMax[1],BBMin[2]); glVertex3f(BBMax[0],BBMax[1],BBMin[2]); glVertex3f(BBMax[0],BBMax[1],BBMax[2]); // x=BBMin[0] glVertex3f(BBMin[0],BBMin[1],BBMin[2]); glVertex3f(BBMin[0],BBMax[1],BBMin[2]); glVertex3f(BBMin[0],BBMax[1],BBMax[2]); glVertex3f(BBMin[0],BBMin[1],BBMax[2]); // x=BBMax[0] glVertex3f(BBMax[0],BBMin[1],BBMin[2]); glVertex3f(BBMax[0],BBMin[1],BBMax[2]); glVertex3f(BBMax[0],BBMax[1],BBMax[2]); glVertex3f(BBMax[0],BBMax[1],BBMin[2]); // z=BBMax[2] glVertex3f(BBMin[0],BBMin[1],BBMax[2]); glVertex3f(BBMin[0],BBMax[1],BBMax[2]); glVertex3f(BBMax[0],BBMax[1],BBMax[2]); glVertex3f(BBMax[0],BBMin[1],BBMax[2]); // z=BBMin[2] glVertex3f(BBMin[0],BBMin[1],BBMin[2]); glVertex3f(BBMax[0],BBMin[1],BBMin[2]); glVertex3f(BBMax[0],BBMax[1],BBMin[2]); glVertex3f(BBMin[0],BBMax[1],BBMin[2]); glEnd(); glPopAttrib(); }