/* Use this program as demoed in class as the starting point for next week's assignment 6. Your job is to devise your own mouse controlled interface for at least viewing the model surface in any orientation you want. You can use either of two possible approaches 1) control the movement of the model while leaving the eye position fixed or 2) leave the model fixed and move the eye around the scene. You do not have to change the underlying Bezier patch mechanism for either of these. In either case you'll need to insert a mouse callback mechanism similar to last week's program. You can directly lift what ever code is appropriate from that assignment. For approach 1, which manipulates the model, you'd use the mouse to control model rotations similar to what the arrow keys alreay do or do it by OpenGL modelview transformations. Approach 2 is more like the way in which the eye position moves us around a scene like last week's asn5. Either approach has its pros and cons but would be adequate for this single model problem. In real situations the choice of which approach is better is usually determined by other factors. One think I forgot to demo that doesn't really affect your assignment but that is useful for understanding the Bezier patch representation is the use of the keyboard number keys. By entering any consecutive digits in the 0-3 rante you select an element in the 4x4 matrix and then use the '-', '=' keys to decrease or increase that particular element while watching the effect on the model's image. See for example the "a view of an asn6 surface" that is linked on the web page and shows a surface modified by changing patch[2][3][1], and a bunch of others. In principal you can set any patch element to pretty much any value to explore the range of single patch Bezier surface shapes. */ /* * Art's adaptation of Samuel R. Buss's rational Bezier patch demo * U/u increase/decrease U samples * V/v increase/decrease V samples * left/right arrow keys control rotation around the y-axis. * up/down arrow keys control rotation around the x-axis. * "r" reset to initial position with no rotation. * "h" halt rotation. * "w" toggle between wireframe or filled mode * "s" toggle between flat and smooth or flat shading. * "a" toggle display of axes * "="/"-" increase or decrease indexed patch value * [0-3][0-3][0-3] 3 consecutive numbers set the patch[][][] index * X/x/Y/y/Z/z increase/decrease eyex, eyey, eyez */ #include #include #include #include #if defined(__APPLE__) || defined(MACOSX) #include #else #include #endif // Control points for a 4x4 Bezier patch. float patch[4][4][4] = { -2, -2, 0, 1, -1, -2, 1.3, 1, 1.5, -2, 1.3, 1, 2, -2, 0, 1, -3, -1, 0, 1, -1, -.9, 2, 1, 1, -.5, 2, 1, 3, -.3, 0, 1, -1.5, .5, 0, 1, -.5, .3, 1, 1, .5, .5, 1, 1, 1.5, 1.2, 0, 1, -2, 1.5, 0, 1, -.7, 1.3, 1.3, 1, .7, 1.9, 1.3, 1, 2, 2.2, 0, 1 }; int Usteps = 10, Vsteps = 10; // number of detail steps of the mesh int index; // index for dynamic patch manipulation GLenum shadeModel = GL_FLAT; // either GL_FLAT or GL_SMOOTH GLenum polygonMode = GL_FILL; // either GL_LINE or GL_FILL float Xang = 0, Yang = 0; // Current rotational angles float dX = 0, dY = 0; // Rotational increments float eyex = 0, eyey = 0, eyez = -20; // relative eye position int draw_axes_flag = 1; // Lighting values float ambientLight[4] = {0.2, 0.2, 0.2, 1.0}; float L0amb[4] = {0.1, 0.1, 0.1, 1.0}; float L0diff[4] = {0.6, 0.6, 0.6, 1.0}; float L0spec[4] = {1.0, 1.0, 1.0, 1.0}; float L0pos[4] = {1.0, 0.0, 1.0, 0.0}; // Directional light 0 float L1amb[4] = {0.1, 0.1, 0.1, 1.0}; float L1diff[4] = {0.6, 0.6, 0.6, 1.0}; float L1spec[4] = {1.0, 1.0, 1.0, 1.0}; float L1pos[4] = {0.0, 1.0, 1.0, 0.0}; // Directional light 1 // Material values float Noemit[4] = {0.0, 0.0, 0.0, 1.0}; float Matspec[4] = {1.0, 1.0, 1.0, 1.0}; float Matdiffu[4] = {0.8, 0.6, 0.3, 1.0}; float Matshiny = 50.0; void KeyboardFunc(unsigned char key, int x, int y) { // regular keys if(isdigit(key)) { // convert digits to a 4x4x4 index index = 0x3F & ((index << 2) + (key & 3)); } else switch(key) { case 27: // Escape key exit(1); case 'z': eyez += 0.1; break; case 'Z': eyez -= 0.1; break; case 'y': eyey += 0.1; break; case 'Y': eyey -= 0.1; break; case 'x': eyex += 0.1; break; case 'X': eyex -= 0.1; break; case 'a': // toggle axes drawing draw_axes_flag ^= 1; break; case 'h': // halt rotation dX = dY = 0.0; break; case 'r': // Reset the rotations to 0 Xang = Yang = dX = dY = 0.0; break; case 's': // toggle between flat and smooth if(shadeModel == GL_FLAT) shadeModel = GL_SMOOTH; else shadeModel = GL_FLAT; break; case 'w': // toggle between wireframe and filled if(polygonMode == GL_LINE) polygonMode = GL_FILL; else polygonMode = GL_LINE; break; case 'u': if(Usteps > 4) Usteps--; break; case 'U': Usteps++; break; case 'v': if(Vsteps > 4) Vsteps--; break; case 'V': Vsteps++; break; case '-': patch[0][0][index] -= 0.1; break; case '=': patch[0][0][index] += 0.1; break; } } void SpecialKeyFunc(int key, int x, int y) { // handle arrow keys switch(key) { case GLUT_KEY_UP: dX -= 0.01; break; case GLUT_KEY_DOWN: dX += 0.01; break; case GLUT_KEY_LEFT: dY -= 0.01; break; case GLUT_KEY_RIGHT: dY += 0.01; break; } } void draw_data(void) { char txt[100], *s; int a, b, c; glPushMatrix(); glDisable(GL_LIGHTING); glColor3f(1,1,1); c = (index>>0) & 3; b = (index>>2) & 3; a = (index>>4) & 3; sprintf(txt, "patch[%d][%d][%d] = %g", a, b, c, patch[a][b][c]); glRasterPos3f(-12,10,20); for(s = txt; *s; s++) glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *s); glEnable(GL_LIGHTING); glPopMatrix(); } void draw_axes(void) { float k = 10 ; float nzero = 0.1 ; glScalef(0.3, 0.3, 0.3); glDisable(GL_LIGHTING) ; glLineWidth(2) ; glBegin(GL_LINES) ; glColor3f(1,0,0) ; glVertex3f(nzero,nzero,nzero) ; glVertex3f(k,nzero,nzero) ; glColor3f(0,1,0) ; glVertex3f(nzero,nzero,nzero) ; glVertex3f(nzero,k,nzero) ; glColor3f(0,0,1) ; glVertex3f(nzero,nzero,nzero) ; glVertex3f(nzero,nzero,k) ; glEnd() ; glLineWidth(1) ; glColor3f(1,1,1) ; glRasterPos3f(k+1,0,0) ; glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'X') ; glRasterPos3f(0,k+1,0) ; glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'Y') ; glRasterPos3f(0,0,k+1) ; glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'Z') ; glEnable(GL_LIGHTING) ; } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glShadeModel(shadeModel); // flat or smooth shading glPolygonMode(GL_FRONT_AND_BACK, polygonMode); // wire or filled // surface materials glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Matdiffu); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Matspec); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, Matshiny); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, Noemit); glPushMatrix(); glTranslatef(eyex, eyey, eyez); // account for eye movement glRotatef(15.0, 1.0,0.0,0.0); // as if looking down from 15 deg // add rotational delta for this step Yang += dY; Xang += dX; // perform the rotation glRotatef(Xang, 1.0, 0.0, 0.0); glRotatef(Yang, 0.0, 1.0, 0.0); // draw the patch glEnable(GL_MAP2_VERTEX_4); glMap2f(GL_MAP2_VERTEX_4, 0,1,4,4, 0,1,16,4, &patch[0][0][0]); glMapGrid2f(Usteps,0,1, Vsteps,0,1); glEvalMesh2(GL_FILL, 0,Usteps, 0,Vsteps); if(draw_axes_flag) draw_axes(); glRotatef(-Yang, 0.0, 1.0, 0.0); // tmp undo rotation so... glRotatef(-Xang, 1.0, 0.0, 0.0); // draw_data is stable draw_data(); glPopMatrix(); glutSwapBuffers(); } void lighting() { glEnable(GL_DEPTH_TEST); // just for kicks try without this glEnable(GL_AUTO_NORMAL); // also essential!!!! glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); // light backside too glFrontFace(GL_CW); // greatly affects speed!!! // Light 0 glLightfv(GL_LIGHT0, GL_AMBIENT, L0amb); glLightfv(GL_LIGHT0, GL_DIFFUSE, L0diff); glLightfv(GL_LIGHT0, GL_SPECULAR, L0spec); glLightfv(GL_LIGHT0, GL_POSITION, L0pos); // Light 1 glLightfv(GL_LIGHT1, GL_AMBIENT, L1amb); glLightfv(GL_LIGHT1, GL_DIFFUSE, L1diff); glLightfv(GL_LIGHT1, GL_SPECULAR, L1spec); glLightfv(GL_LIGHT1, GL_POSITION, L1pos); } void reshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(40.0, (float)w/h, 1.0, 30.0); glMatrixMode(GL_MODELVIEW); } int main(int argc, char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowPosition(40, 60); glutInitWindowSize(640, 480); glutCreateWindow("Nurbs demo"); lighting(); reshape(640, 480); glutKeyboardFunc(KeyboardFunc); glutSpecialFunc(SpecialKeyFunc); glutReshapeFunc(reshape); glutIdleFunc(display); glutDisplayFunc(display); glutMainLoop(); return(0); }