/* 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); 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); } /* I don't know if this really looks like light blue nylon; it probably doesn't, but I tried. */ void light_blue_nylon() { const float d = 255.0; twError(); // Got these values from /usr/lib/X11/rgb.txt for cornflower blue GLfloat ambient_diffuse[] = { 100/d, 149/d, 237/d, 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); twError(); } void steel() { const float d = 255.0; twError(); // Got these values from /usr/lib/X11/rgb.txt, using LightSteelBlue // (110,123,139), then modified to be a bit less blue, by moving them // all towards their average value of 124. GLfloat ambient_diffuse[] = { 117/d, 124/d, 132/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); twError(); } void cube_and_ball(GLfloat height) { // debugging only glPushMatrix(); glTranslatef(10,height,0); glutSolidSphere(10,20,20); glTranslatef(20,0,0); glutSolidCube(10); glPopMatrix(); } // 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() { twError(); steel(); // set a material // 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(); // set a material draw_bezier_surface(8,flag[0]); glPopMatrix(); glDisable(GL_TEXTURE_2D); twError(); } /* I don't know if this really looks like sunlight, but it's just slightly yellow, so it's at least interesting. */ void sun() { GLfloat direction[] = {10,20,10,0}; GLfloat sunlight[] = {0.8,0.8,0.7,1}; // decided to switch to gray light, so that the colors were easier to // adjust twGrayLight(GL_LIGHT0,direction,0.4,0.8,1); return; twError(); glEnable(GL_LIGHT0); /* light0 is the sun */ glLightfv(GL_LIGHT0, GL_POSITION, direction); glLightfv(GL_LIGHT0, GL_AMBIENT, sunlight); glLightfv(GL_LIGHT0, GL_DIFFUSE, sunlight); glLightfv(GL_LIGHT0, GL_SPECULAR, sunlight); twError(); } GLfloat global_ambient[] = {0.7,0.7,0.7,1}; /* ================================================================ */ void display() { twDisplayInit(0,0,0); twCamera(); glPushAttrib(GL_ALL_ATTRIB_BITS); twError(); 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 */ // debugging only // glDisable(GL_TEXTURE_2D); steel(); cube_and_ball(0); light_blue_nylon(); cube_and_ball(20); sun(); // sets up lighting draw_flag(); // may enable texturing twError(); 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(); }