/* 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 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_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 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}; glEnable(GL_AUTO_NORMAL); /* automatically compute normals */ 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); // set up grid and generate the desired surface glMapGrid2f(nsteps, 0, 1, nsteps, 0, 1); if(Decal) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glBindTexture(GL_TEXTURE_2D,textureIDs[0]); } else { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glBindTexture(GL_TEXTURE_2D,textureIDs[1]); } if(Texture) glEnable(GL_TEXTURE_2D); glEnable(GL_NORMALIZE); if(Wire) glEvalMesh2(GL_LINE, 0, nsteps, 0, nsteps); else glEvalMesh2(GL_FILL, 0, nsteps, 0, nsteps); } /* I don't know if this really looks like light blue nylon; it probably doesn't, but I tried. */ void light_blue_nylon() { // Got these values from /usr/lib/X11/rgb.txt //GLfloat ambient_diffuse[] = { 135/255.0, 206/255.0, 235/255.0, 1.0 }; GLfloat ambient_diffuse[] = { 155/255.0, 226/255.0, 255/255.0, 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() { // Got these values from /usr/lib/X11/rgb.txt, using LightSlateGray GLfloat ambient_diffuse[] = { 119/255.0, 136/255.0, 153/255.0, 1 }; //GLfloat ambient_diffuse[] = { 1, 1, 1, 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 height 100 (square cross-section of 1 unit) at the // origin, using steel() and a flag of light_blue_nylon(). Maybe the // units are inches, for a short flag? void draw_flag() { steel(); // draw flagpole. This is a tall square pole. glPushMatrix(); glScalef(1,100,1); glTranslatef(0,0.5,0); glutSolidCube(1); glPopMatrix(); // draw knob at the top. glPushMatrix(); glTranslatef(0,100.5,0); glutSolidSphere(1,20,20); glPopMatrix(); // draw flag glPushMatrix(); glTranslatef(0,100-30,0); glScalef(30,30,30); light_blue_nylon(); draw_bezier_surface(8,flag[0]); glPopMatrix(); } void sun() { GLfloat direction[] = {10,200,10,0}; GLfloat ambient_diffuse[] = {1,1,0.9,1}; GLfloat specular[] = {1,1,0.9,1}; glEnable(GL_LIGHT0); /* light0 is the sun */ glLightfv(GL_LIGHT0, GL_POSITION, direction); glLightfv(GL_LIGHT0, GL_AMBIENT_AND_DIFFUSE, ambient_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, specular); } GLfloat global_ambient[] = {0.7,0.7,0.7,1}; /* ================================================================ */ void display() { twDisplayInit(); twCamera(); glPushAttrib(GL_ALL_ATTRIB_BITS); glColor3f(0,1,0); glEnable(GL_LIGHTING); // Doesn't matter right now, but if we add another light... glShadeModel(GL_SMOOTH); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient); glLineWidth(2); /* lines are this many pixels wide */ sun(); draw_flag(); 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; } 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,100,-10,10); twMainInit(); twKeyCallback('w',keys,"toggle wire frame"); twKeyCallback('t',keys,"toggle texture mapping"); twKeyCallback('d',keys,"toggle decal"); glutMainLoop(); }