/* Demo of defining the front of a quadilateral for use in material and lighting. This demo is similar to FrontBack, so look at the documentation for that one. The answer is that none of these flat quads looks "right". You really have to draw the quad twice, so that you never have to deal with back facets. Implemented Fall 2004 Scott D. Anderson */ #include #include twTriple Quad[4] = { {-1,-1,0}, // left, bottom, front {+1,-1,0}, // right, bottom, front {-1,+1,0}, // left, top, front {+1,+1,0}, // right, top, front }; bool CullFace = false; bool Amb = true; bool Diff = true; bool Spec = true; bool LocalViewer = false; bool TwoSided = false; bool Back = true; void drawQuad(int a, int b, int c, int d) { // twTriple N; // twPlaneNormal(N,Quad[a],Quad[b],Quad[c]); glBegin(GL_QUADS); // glNormal3f(N[0],N[1],N[2]); glVertex3fv(Quad[a]); glVertex3fv(Quad[b]); glVertex3fv(Quad[c]); glVertex3fv(Quad[d]); glEnd(); glPushAttrib(GL_ALL_ATTRIB_BITS); glDisable(GL_LIGHTING); glColor3f(0,0,1); twDrawString(Quad[a][0],Quad[a][1],Quad[a][2],"A"); twDrawString(Quad[b][0],Quad[b][1],Quad[b][2],"B"); twDrawString(Quad[c][0],Quad[c][1],Quad[c][2],"C"); twDrawString(Quad[d][0],Quad[d][1],Quad[d][2],"D"); glPopAttrib(); } void display(void) { twDisplayInit(); twCamera(); if(CullFace) { glEnable(GL_CULL_FACE); } else { glDisable(GL_CULL_FACE); } glEnable(GL_NORMALIZE); GLfloat lightDir[] = { -1, 0, 1, 0}; // from back right twGrayLight(GL_LIGHT0,lightDir,1,1,1); glEnable(GL_LIGHTING); if(LocalViewer) { glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,1); } else { glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,0); } if(TwoSided) { glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,1); } else { glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,0); } twTriple black = {0,0,0}; twTriple red = {1,0,0}; twTriple green = {0,1,0}; twTriple blue = {0,0,1}; twTriple yellow50 = {0.5,0.5,0}; twTriple cyan50 = {0,0.5,0.5}; twTriple magenta50 = {0.5,0,0.5}; glMaterialfv(GL_FRONT,GL_AMBIENT,Amb?red:black); glMaterialfv(GL_FRONT,GL_DIFFUSE,Diff?green:black); glMaterialfv(GL_FRONT,GL_SPECULAR,Spec?blue:black); glMaterialf(GL_FRONT,GL_SHININESS,10); if(Back) { glMaterialfv(GL_BACK,GL_AMBIENT,Amb?magenta50:black); glMaterialfv(GL_BACK,GL_DIFFUSE,Diff?yellow50:black); glMaterialfv(GL_BACK,GL_SPECULAR,Spec?cyan50:black); glMaterialf(GL_BACK,GL_SHININESS,10); } else { glMaterialfv(GL_BACK,GL_AMBIENT,Amb?red:black); glMaterialfv(GL_BACK,GL_DIFFUSE,Diff?green:black); glMaterialfv(GL_BACK,GL_SPECULAR,Spec?blue:black); glMaterialf(GL_BACK,GL_SHININESS,10); } glutSolidSphere(1,32,32); // Upper right quad is proper: CCW and N=(0,0,1); glPushMatrix(); glTranslatef(+2,+2,0); glNormal3f(0,0,1); drawQuad(0,1,3,2); glPopMatrix(); // Upper left quad is bad: CW. It disappears with backface culling glPushMatrix(); glTranslatef(-2,+2,0); glNormal3f(0,0,1); drawQuad(0,2,3,1); glPopMatrix(); // Lower left quad is bad: N=(0,0,-1). It doesn't disappear with // backface culling, but we only see the ambient, not the // ambient+diffuse glPushMatrix(); glTranslatef(-2,-2,0); glNormal3f(0,0,-1); drawQuad(0,1,3,2); glPopMatrix(); // Lower right is a proper cube. Looks just like the upper left glPushMatrix(); glTranslatef(+2,-2,0); glScalef(2,2,0.1); glutSolidCube(1); glPopMatrix(); glPushAttrib(GL_ALL_ATTRIB_BITS); glDisable(GL_LIGHTING); glColor3f(0,0,1); twDrawString(+2,+1.5,0,"CCW and normal=+z"); twDrawString(-2,+1.5,0,"CW"); twDrawString(-2,-2.5,0,"CCW, but normal=-z"); twDrawString(+2,-2.5,1,"cube"); twDrawString(0,-3.5,0,"TwoSide = %s",TwoSided?"on":"off"); twDrawString(0,-3.7,0,"CullFace = %s",CullFace?"on":"off"); twDrawString(0,-3.9,0,"LocalViewer = %s",LocalViewer?"on":"off"); twDrawString(0,-4.1,0,"Ambient = %s",Amb?"on":"off"); twDrawString(0,-4.3,0,"Diffuse = %s",Diff?"on":"off"); twDrawString(0,-4.5,0,"Specular = %s",Spec?"on":"off"); glPopAttrib(); glFlush(); glutSwapBuffers(); } void keys(unsigned char k, int x, int y) { switch(k) { case 'a': Amb = !Amb; break; case 'd': Diff = !Diff; break; case 's': Spec = !Spec; break; case 'c': CullFace = !CullFace; break; case '1': { twTriple Y={0,1,0}; twRotateViewpoint(180,Y); } break; case 'l': LocalViewer = !LocalViewer; break; case '2': TwoSided = !TwoSided; break; case 'b': Back = !Back; break; case 'p': printf("\nAmbient %s\nDiffuse %s\nSpecular %s\nCullFace %s\nLocalViewer %s\nTwoSided %s\nBack Material %s\n", Amb?"on":"off", Diff?"on":"off", Spec?"on":"off", CullFace?"on":"off", LocalViewer?"on":"off", TwoSided?"on":"off", Back?"on":"off"); break; } glutPostRedisplay(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); twInitWindowSize(500,600); glutCreateWindow(argv[0]); glutDisplayFunc(display); twBoundingBox(-2,+2,-2,+2,-1,+1); // a lie twMainInit(); twKeyCallback('c',keys,"toggle backface culling"); twKeyCallback('a',keys,"toggle Ambient = red"); twKeyCallback('d',keys,"toggle Diffuse = green"); twKeyCallback('s',keys,"toggle Specular = blue"); twKeyCallback('1',keys,"180 degree rotation"); twKeyCallback('2',keys,"toggle two-sided lighting"); twKeyCallback('l',keys,"toggle local viewer"); twKeyCallback('b',keys,"toggle back material"); twKeyCallback('p',keys,"print settings"); glutMainLoop(); return 0; }