/* Demonstrates lighting of a flat patch, to help figure out how normals are calculated by GL_AUTO_NORMAL. The answer is that they are calculated as s x t: the "s" vector crossed with the "t" vector. Therefore, if "s" increases left to right and "t" increases bottom to top, the normal vector will point towards you. Alternatively, the "s" vector could increase top to bottom and the "t" vector could increase left to right, and you'd get the normal vectror facing towards you. This is convenient if you want the upper left corner to be at parameters (0,0). I'm not yet sure what determines whether the quads face backwards or forwards (for backface culling). Written by Scott D. Anderson scott.anderson@acm.org Fall 2005 */ #include #include #include // Faces backwards so culled by backface culling, but normal points forwards GLfloat FlatCP1[2*2][3] = { {0, 0, 0}, // lower left A {1, 0, 0}, // lower right B {0, 1, 0}, // upper left D {1, 1, 0}, // upper right C }; // Faces forward so not culled by backface culling, but the normal points backwards GLfloat FlatCP2[2*2][3] = { {0, 1, 0}, // upper left D {1, 1, 0}, // upper right C {0, 0, 0}, // lower left A {1, 0, 0}, // lower right B }; // Faces backward, culled. Normal points forward. GLfloat FlatCP3[2*2][3] = { {0, 1, 0}, // upper left D {0, 0, 0}, // lower left A {1, 1, 0}, // upper right C {1, 0, 0}, // lower right B }; // Faces backward, culled, normal points backward. GLfloat FlatCP4[2*2][3] = { {1, 1, 0}, // upper right C {0, 1, 0}, // upper left D {1, 0, 0}, // lower right B {0, 0, 0}, // lower left A }; // Faces backward, normal points forward GLfloat FlatCP5[2*2][3] = { {1, 1, 0}, // upper right C {0, 1, 0}, // upper left D {1, 0, 0}, // lower right B {0, 0, 0}, // lower left A }; // Faces backward, normal points forward GLfloat FlatCP6[2*2][3] = { {1, 0, 0}, // lower right B {1, 1, 0}, // upper right C {0, 0, 0}, // lower left A {0, 1, 0}, // upper left D }; void BezierPatch(GLfloat* cp) { int hsteps = 3; int vsteps = 3; glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 2, 0, 1, 6, 2, cp); glEnable(GL_MAP2_VERTEX_3); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); glMapGrid2f(hsteps,0,1,vsteps,0,1); glEvalMesh2(GL_FILL,0,hsteps,0,vsteps); twError(); } bool CullFace = false; // the OpenGL default bool TwoSided = false; // the OpenGL default void display(void) { twDisplayInit(); twCamera(); twError(); GLfloat light0Pos[] = {0, 0, 1, 0}; twGrayLight(GL_LIGHT0,light0Pos,0.2,0.9,0); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,1); if(CullFace) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); if(TwoSided) { glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,1); } else { glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,0); // OpenGL default is one-sided lighting } glShadeModel(GL_SMOOTH); twAmbient(0); twTriple objColor = {0.4, 0.9, 0.8}; twColor(objColor,0.9,20); glPushMatrix(); glTranslatef(0.5,0.51,0); glutSolidSphere(0.5,20,20); // glutSolidCube(0.5); glPopMatrix(); glPushMatrix(); glTranslatef(-1,-1,0); glBegin(GL_QUADS); glNormal3f(0,0,1); glVertex3fv(FlatCP1[0]); // A glVertex3fv(FlatCP1[1]); // B glVertex3fv(FlatCP1[3]); // C glVertex3fv(FlatCP1[2]); // D glEnd(); twDrawString(0,-0.5,0,"Flat Quad"); glPopMatrix(); glPushMatrix(); glTranslatef(1,1,0); twError(); BezierPatch(FlatCP1[0]); twError(); twDrawString(0,-0.5,0,"Patch 1"); glPopMatrix(); glPushMatrix(); glTranslatef(1,-1,0); twError(); BezierPatch(FlatCP2[0]); twError(); twDrawString(0,-0.5,0,"Patch 2"); glPopMatrix(); glPushMatrix(); glTranslatef(-1,1,0); twError(); BezierPatch(FlatCP6[0]); twError(); twDrawString(0,-0.5,0,"Patch 6"); glPopMatrix(); glFlush(); glutSwapBuffers(); } void keys(unsigned char k, int x, int y) { switch(k) { case 'c': CullFace = !CullFace; break; case '0': { twTriple Y={0,1,0}; twRotateViewpoint(180,Y); } break; case '1': TwoSided = false; break; case '2': TwoSided = true; break; } glutPostRedisplay(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); twInitWindowSize(500,300); glutCreateWindow(argv[0]); glutDisplayFunc(display); twBoundingBox(-1,2,-1,1,0,0); twMainInit(); twKeyCallback('c',keys,"toggle backface culling"); twKeyCallback('0',keys,"180-degree turn"); twKeyCallback('1',keys,"one-sided lighting"); twKeyCallback('2',keys,"two-sided lighting"); twKeyCallback('l',keys,"toggle local viewer"); glutMainLoop(); return 0; }