/* Simple demo of a 2D surface in a 3D world, where the surface is defined by Bezier curves. This demo uses material for the flag and enables lighting. Scott D. Anderson Fall 2000 original Fall 2003 adapted to use TW */ #include #include #include #include bool Texture = false; // whether to texture-map bool Decal = false; // whether to use Decal or Modulate bool Linear = false; // whether to use Linear or Nearest bool Wire = true; // whether to use wireframe or fill /* ================================================================ Texture variables */ GLuint textureIDs[2]; void init() { glGenTextures(2,textureIDs); glBindTexture(GL_TEXTURE_2D,textureIDs[0]); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); twUSflag(); // sends the flag texture down the pipeline glBindTexture(GL_TEXTURE_2D,textureIDs[1]); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); twUSflag(); // sends the flag texture down the pipeline } /* ==================================================================== */ GLfloat flag[16][3] = { {0.0, 0.0, 0.0}, /* ll corner */ {0.1, 0.2, 0.0}, /* ll edge */ {0.1, 0.8, 0.0}, /* ul edge */ {0.0, 1.0, 0.0}, /* ul corner */ {0.2, 0.1, 0.4}, /* ll edge, curving forward */ {0.2, 0.2, 0.4}, /* ll interior corner */ {0.2, 0.8, 0.3}, /* ul interior corner */ {0.2, 0.9, 0.3}, /* top left edge */ {0.8, -0.1, -0.8}, /* lr edge, curving forward from behind */ {0.8, 0.0, -0.7}, /* lr interior corner */ {0.7, 0.8, -0.7}, /* ur interior corner */ {0.7, 0.9, -0.7}, /* ur edge */ {0.9, 0.3, 0.0}, /* lr corner */ {0.8, 0.4, -0.1}, /* lr edge */ {0.8, 0.8, 0.0}, /* ur edge */ {0.9, 0.9, -0.1} /* ur corner */ }; // This draws the whole surface, using a mesh with `nsteps' in each direction void draw_bezier_surface(int nsteps, GLfloat* control_points) { // Look carefully at these. The flag control points start in the // lower left! GLfloat texture_cp[8]={0,0.8125, 0,0, 0.77,0.8125, 0.77,0}; glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, control_points); // Add textures glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2, texture_cp); glEnable(GL_MAP2_VERTEX_3); glEnable(GL_MAP2_TEXTURE_COORD_2); glEnable(GL_AUTO_NORMAL); /* automatically compute normals */ // set up grid and generate the desired surface glMapGrid2f(nsteps, 0, 1, nsteps, 0, 1); if(Linear) { glBindTexture(GL_TEXTURE_2D,textureIDs[1]); } else { glBindTexture(GL_TEXTURE_2D,textureIDs[0]); } // Apparently, glTexEnvf isn't captured by texture binding; you have // to say it here. if(Decal) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); } else { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } GLfloat param; glGetTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,¶m); printf("Mode = %s\n", param==GL_MODULATE ? "MODULATE" : "DECAL"); if(Texture) { glEnable(GL_TEXTURE_2D); } else { glDisable(GL_TEXTURE_2D); } glEnable(GL_NORMALIZE); if(Wire) glEvalMesh2(GL_LINE, 0, nsteps, 0, nsteps); else glEvalMesh2(GL_FILL, 0, nsteps, 0, nsteps); } /* A gray material, so it won't muck up the texture colors. */ void gray(float v) { GLfloat ambient_diffuse[] = { v, v, v, 1.0 }; GLfloat specular[] = { 1, 1, 1, 1 }; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ambient_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, specular); // shininess is in the range [0,128]. glMaterialf(GL_FRONT, GL_SHININESS, 10.0); } void steel() { const float d = 255.0; // Got these values from /usr/lib/X11/rgb.txt, using LightSlateGray. // It has a slight bluish cast to it. GLfloat ambient_diffuse[] = { 119/d, 136/d, 153/d, 1 }; GLfloat specular[] = { 1, 1, 1, 1 }; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ambient_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, specular); // shininess is in the range [0,128]. glMaterialf(GL_FRONT, GL_SHININESS, 100.0); } // Draws a flagpole of given height (square cross-section of 1 unit) at // the origin, using steel() and a gray flag(). Maybe the units are // inches, for a short flag? const int POLE_HEIGHT = 100; void drawFlagAndPole() { steel(); // draw flagpole. This is a tall square pole. glPushMatrix(); glScalef(1,POLE_HEIGHT,1); glTranslatef(0,0.5,0); glutSolidCube(1); glPopMatrix(); // draw knob at the top glPushMatrix(); glTranslatef(0,POLE_HEIGHT,0); glutSolidSphere(1,20,20); glPopMatrix(); const int FLAG_HEIGHT = 30; // draw flag glPushMatrix(); glTranslatef(0,POLE_HEIGHT-FLAG_HEIGHT,0); glScalef(FLAG_HEIGHT,FLAG_HEIGHT,FLAG_HEIGHT); gray(0.3); draw_bezier_surface(16,flag[0]); glPopMatrix(); // for debugging only glPushMatrix(); glTranslatef(15,15,0); glutSolidSphere(5,20,20); glPopMatrix(); } void light() { // light comes from in front, so we'll get plenty of light on the flag GLfloat direction[] = {0,0,1,0}; twGrayLight(GL_LIGHT0,direction,0,1,0); glLightfv(GL_LIGHT0, GL_POSITION, direction); glEnable(GL_LIGHT0); } /* ================================================================ */ void display() { twDisplayInit(); twCamera(); glPushAttrib(GL_ALL_ATTRIB_BITS); glColor3f(0,1,0); glEnable(GL_LIGHTING); glShadeModel(GL_SMOOTH); twAmbient(0.3); glLineWidth(2); /* lines are this many pixels wide */ light(); drawFlagAndPole(); glPopAttrib(); glFlush(); glutSwapBuffers(); } /* ================================================================ */ void keys(unsigned char key, int x, int y) { switch(key) { case 'w': Wire = !Wire; break; case 't': Texture = !Texture; break; case 'd': Decal = !Decal; break; case 'l': Linear = !Linear; break; } glutPostRedisplay(); } /* ================================================================ */ int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); twBoundingBox(0,30,0,POLE_HEIGHT+1,-10,10); twMainInit(); twKeyCallback('w',keys,"toggle wire frame"); twKeyCallback('t',keys,"toggle texture mapping"); twKeyCallback('d',keys,"toggle decal/modulate"); twKeyCallback('l',keys,"toggle linear/nearest"); glutMainLoop(); }