/************************************************************** * $Id: hw2.c,v 1.1 1998/03/02 16:22:52 yap Exp yap $ * $Date: 1998/03/02 16:22:52 $ * * Visualization -- OpenGL Project #2 * Author: Chen Li * Chee Yap modified for hw2 to include: * (a) textures, * (b) a slider input * (c) changing sensitivity of rotation with slider **************************************************************/ #include #include #include #include #include // define some global consts #define MY_CUBE1_LIST 1 #define MY_CUBE2_LIST 2 int mainWin, win1, win2, win3, win4; //yap: 1-D texture GLfloat sliderPos=0.5; // between 0 and 1 (this is the instantaneous x-position) GLfloat sliderVal=0.5; // between 0 and 1 (this is the selected x-position) char sliderPosition[30]; // sliderPosition is the corresponding string int length, i; char sliderValue[30]; // sliderValue is the corresponding string GLfloat eyeplane[] = {0.0, 0.0, 1.0, 0.0}; GLint texlen = 32; GLfloat tex[][3] = { {1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}, {0.7, 0.7, 0.7}, {0.7, 0.7, 0.7}, {0.7, 0.7, 0.7}, {0.7, 0.7, 0.7}, {0.7, 0.7, 0.7}, {0.7, 0.7, 0.7}, {0.7, 0.7, 0.7}, {0.7, 0.7, 0.7}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}; // define some labels shown with the buttons char *label1 = "FLAT"; char *label2 = "ROTATE"; char *label3 = "LIGHT"; char *label4 = "SLIDER "; // define some color constants #define BLACK {0.0,0.0,0.0} #define RED {1.0,0.0,0.0} #define GREEN {0.0,1.0,0.0} #define BLUE {0.0,0.0,1.0} #define YELLOW {1.0,1.0,0.0} #define MAGENTA {1.0,0.0,1.0} #define CYAN {0.0,1.0,1.0} #define WHITE {1.0,1.0,1.0} #define UNKNOWN {0.2,0.3,0.5} //yap GLfloat DisplayButtonColors[] = {1.0, 1.0, 0.0}; // define some cube constants GLfloat vertices[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0}, {1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}}; // define the normals on vertices GLfloat normals[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0}, {1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}}; // define the colors on vertices GLfloat cube1_colors[][3] = {UNKNOWN, RED, YELLOW, GREEN, BLUE, MAGENTA, WHITE, CYAN }; // define a different set of colors for another cube GLfloat cube2_colors[][3] = {{0.3,0.2,0.5}, {.8,0.1,0.1}, {.4,.4,0.2}, {0.1,.8,0.1}, {.1,.1,.8} ,{.4,0.2,.4}, {1.0,1.0,.3}, {0.0,.9 ,1.0} }; // define some global states static GLfloat axis1[] = {1.0,1.0,1.0}; static GLfloat w1[] = {1.0, 1.0, 1.0}; static GLfloat theta1[] = {0.0, 0.0, 0.0}; static GLfloat axis2[] = {0.0,1.0,0.0}; static GLfloat w2[] = {1.0, 1.0, 1.0}; static GLfloat theta2[] = {0.0, 0.0, 0.0}; int spinOn=1, smoothShading=1, lightOff=1, texture=1; // define light parameters GLfloat global_ambient[] = {0.2, 0.2, 0.2, 1.0}; // Global ambient term GLfloat light0_diffuse[] = {0.0, 1.0, 0.0, 1.0}; // Green diffuse light GLfloat light0_specular[] = {1.0, 1.0, 1.0, 0.0}; // White specular light GLfloat light0_position[] = {1.0, 1.0, 1.0, 0.0}; // Infinite light location GLfloat light1_diffuse[] = {1.0, 0.0, 0.0, 1.0}; // Red diffuse light GLfloat light1_specular[] = {1.0, 1.0, 1.0, 0.0}; // White specular light GLfloat light1_position[] = {-1.0, 1.0, 1.0, 0.0}; // Infinite light location GLfloat light2_diffuse[] = {0.0, 0.0, 1.0, 1.0}; // Blue diffuse light GLfloat light2_specular[] = {1.0, 1.0, 1.0, 0.0}; // White specular light GLfloat light2_position[] = {0.0, -1.0, 1.0, 0.0}; // Infinite light location // declare some functions in advance void drawVertLine(GLfloat x); //yap void polygon1(int a, int b, int c , int d); void polygon2(int a, int b, int c , int d); void drawButton(); void drawPressedButton(); void buildCube(); void calculateRotationForCube1(); void calculateRotationForCube2(); GLfloat* crossProduct(float x1, float y1, float z1, float x2, float y2, float z2); float dotProduct(float x1, float y1, float z1, float x2, float y2, float z2); float getAngle(float x1, float y1, float z1, float x2, float y2, float z2); /*************************************************************** * OpenGL/GLUT callback functions ***************************************************************/ static void Idle( void ) { /* update animation vars */ if (spinOn) { calculateRotationForCube1(); calculateRotationForCube2(); } // redisplay the subwindows glutSetWindow(win1); glutPostRedisplay(); glutSetWindow(win2); glutPostRedisplay(); glutSetWindow(win3); glutPostRedisplay(); //yap glutSetWindow(win4); glutPostRedisplay(); // set the current window back to the main window and mark redisplay glutSetWindow(mainWin); glutPostRedisplay(); } static void Display( void ) { /* display callback, clear frame buffer and z buffer, rotate cube and draw, swap buffers */ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // use smooth or flat shadings if (smoothShading) glShadeModel(GL_SMOOTH); else glShadeModel(GL_FLAT); // enable/disable lightings if (lightOff) glDisable(GL_LIGHTING); else glEnable(GL_LIGHTING); // enable/disable texture if (texture) glEnable(GL_TEXTURE_1D); else glDisable(GL_TEXTURE_1D); // draw the inner cube glPushMatrix(); glRotatef(theta1[0], 1.0, 0.0, 0.0); glRotatef(theta1[1], 0.0, 1.0, 0.0); glRotatef(theta1[2], 0.0, 0.0, 1.0); glPolygonMode(GL_FRONT, GL_FILL); glCallList(MY_CUBE1_LIST); glPopMatrix(); // draw the outer cube glPushMatrix(); glScalef(3.0, 3.0, 3.0); glRotatef(theta2[0], 1.0, 0.0, 0.0); glRotatef(theta2[1], 0.0, 1.0, 0.0); glRotatef(theta2[2], 0.0, 0.0, 1.0); glPolygonMode(GL_FRONT, GL_LINE); glCallList(MY_CUBE2_LIST); glPopMatrix(); // force refresh glFlush(); glutSwapBuffers(); } static void Reshape( int width, int height ) { // printf("width=%d, height=%d \n", width, height); glViewport( 0, 0, width, height ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); // glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 ); glFrustum( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( 0.0, 0.0, -15.0 ); } static void Key( unsigned char key, int x, int y ) { switch (key) { case 27: exit(0); break; case 'r': case 'R': spinOn = 1 - spinOn; //toggle between rotate and spin mode break; case 's': case 'S': smoothShading = 1- smoothShading; //toggle between the shading modes break; case 'l': case 'L': lightOff = 1 - lightOff; // turn on/off light break; // yap: add textures: case 't': case 'T': texture = 1 - texture; // turn on/off texture break; } glutPostRedisplay(); } static void Mouse(int button, int state, int x, int y) { /* mouse callback, specify the axis and degree of rotation */ static int x1, y1, x2, y2, deltaX, deltaY; GLfloat *tmp = NULL; float angSpeed; int i; if (((button==GLUT_MIDDLE_BUTTON) || (button==GLUT_LEFT_BUTTON)) && state == GLUT_DOWN) { x1 = x - 200; y1 = - y + 200; // printf("x1=%d, y1=%d\n", x1, y1); } if(button==GLUT_MIDDLE_BUTTON && state == GLUT_UP) { x2 = x - 200; y2 = -y + 200; deltaX = x2 - x1; deltaY = y2 - y1; if ((abs(deltaX) <=1 ) && (abs(deltaY) <=1 ) ) return; glPushMatrix(); tmp = crossProduct(x1, y1, 300*sliderVal, x2, y2, 300*sliderVal); axis1[0] = tmp[0]; axis1[1] = tmp[1]; axis1[2] = tmp[2]; angSpeed = (spinOn)? getAngle(x1, y1, 300*sliderVal,x2, y2, 300*sliderVal)/20.0 : getAngle(x1, y1, 300*sliderVal,x2, y2, 300*sliderVal)/ 4.0; for (i=0; i<3; i++) { w1[i] = angSpeed*axis1[i]; } /* printf("x1=%d, y1=%d, x2=%d, y2=%d \n", x1, y1, x2, y2); printf("The axis for rotation one is %f, %f, %f. \n", axis1[0], axis1[1], axis1[2]); printf("The inner rotation speed is %f %f %f \n\n", w1[0], w1[1], w1[2]); */ if (!spinOn) { // we do one-time rotation calculateRotationForCube1(); glutPostRedisplay(); // restore to angular speed for (i=0; i<3; i++) w1[i] /= 5.0; } } if(button==GLUT_LEFT_BUTTON && state == GLUT_UP) { x2 = x - 200; y2 = -y + 200; deltaX = x2 - x1; deltaY = y2 - y1; if ((abs(deltaX) <=1 ) && (abs(deltaY) <=1 ) ) return; tmp = crossProduct(x1, y1, 300*sliderVal, x2, y2, 300*sliderVal); axis2[0] = tmp[0]; axis2[1] = tmp[1]; axis2[2] = tmp[2]; //yap: z value is determined by 300*sliderVal angSpeed = (spinOn)? getAngle(x1, y1, 300*sliderVal, x2, y2, 300*sliderVal) / 20.0 : getAngle(x1, y1, 300*sliderVal, x2, y2, 300*sliderVal) / 4.0; for (i=0; i<3; i++) { w2[i] = angSpeed*axis2[i]; } /* printf("x1=%d, y1=%d, x2=%d, y2=%d \n", x1, y1, x2, y2); printf("The axis for rotation two is %f, %f, %f. \n", axis2[0], axis2[1], axis2[2]); printf("The outer rotation speed is %f %f %f\n\n", w2[0], w2[1], w2[2]); */ if (!spinOn) { // we do one-time rotation calculateRotationForCube2(); glutPostRedisplay(); // restore to angular speed for (i=0; i<3; i++) w2[i] /= 5.0; } } } static void Init( void ) { //yap: initial values for slider position/value sprintf(sliderPosition,"Pos=%f\n", sliderPos); sprintf(sliderValue,"Val=%f\n", sliderVal); //initialize options spinOn=1; smoothShading=1; lightOff=1; texture=1; //yap: texture // set up texture environment: glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // set up texture: glTexImage1D(GL_TEXTURE_1D, 0, 3, texlen, 0, GL_RGB, GL_FLOAT, tex); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGenfv(GL_S, GL_EYE_PLANE, eyeplane); glEnable(GL_TEXTURE_GEN_S); //yap: do this in Display: // glEnable(GL_TEXTURE_1D); /* setup lighting, etc */ // glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glEnable(GL_LIGHT2); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); glMaterialf(GL_FRONT, GL_SHININESS, 100.0); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular); glLightfv(GL_LIGHT0, GL_POSITION, light0_position); glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse); glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular); glLightfv(GL_LIGHT1, GL_POSITION, light1_position); glLightfv(GL_LIGHT2, GL_DIFFUSE, light2_diffuse); glLightfv(GL_LIGHT2, GL_SPECULAR, light2_specular); glLightfv(GL_LIGHT2, GL_POSITION, light2_position); // build some display lists buildCube(); } void right_menu(int id) { glutIdleFunc(NULL); if(id == 1) exit(0); if(id == 2) Init(); if(id == 3) texture = 1 - texture; else Display(); glutIdleFunc(Idle); glutPostRedisplay(); } void displayButton(char* label, int state) { int len, i; glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glColor3fv(DisplayButtonColors); glPushMatrix(); glTranslatef(-40, 0, 0); glScalef(8.0, 8.0, 1.0); if (state) drawButton(); else drawPressedButton(); glScalef(.125, .125, 1.0); glTranslatef(20, -5.0, 0.0); glScalef(0.1, 0.1, 0.1); len = (int) strlen(label); for (i = 0; i < len; i++) { glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, label[i]); } glPopMatrix(); glFlush(); glutSwapBuffers(); } void displayButton1(void) { displayButton(label1, smoothShading); } static void flatButtonMouse(int button, int state, int x, int y) { /* mouse callback, to toggle the flat shading option */ if (state == GLUT_DOWN) { smoothShading = 1 - smoothShading; } } void displayButton2(void) { displayButton(label2, spinOn); } static void spinButtonMouse(int button, int state, int x, int y) { /* mouse callback, to toggle the spin/rotate mode */ if (state == GLUT_DOWN) { spinOn = 1 - spinOn; } } void displayButton3(void) { displayButton(label3, lightOff); } void displayButton4(void) { int i, len; glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glColor3fv(DisplayButtonColors); glPushMatrix(); glTranslatef(-120, 0, 0); // x=-120 makes a box touching the left boundary! glPushMatrix(); glScalef(80.0, 8.0, 1.0); drawButton(); drawVertLine(sliderVal); // current slider value glPopMatrix(); // i.e., glScalef(0.0125, 0.125, 1.0); glTranslatef(85, -5.0, 0.0); // get to start position for lettering glScalef(0.1, 0.1, 0.1); // get correct scale for lettering len= (int) strlen(label4); for (i=0; i160) x = 160; if (x<0) x = 0; sliderVal = ((float)x)/160; sprintf(sliderValue,"Val=%f", sliderVal); // printf("%s\n",sliderValue); glutDisplayFunc(displayButton4); } } static void sliderMotion(int x, int y) { /* mouse callback for setting x value of slider */ int len, i; if (x>160) x = 160; if (x<0) x = 0; sliderPos = ((float)x)/160; sprintf(sliderPosition,"Pos=%f", sliderPos); // printf("sliderMotion:%s\n", sliderPosition); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glColor3fv(DisplayButtonColors); glPushMatrix(); glTranslatef(-120, 0, 0); // x=-120 makes a box touching the left boundary! glPushMatrix(); glScalef(80.0, 8.0, 1.0); drawButton(); drawVertLine(sliderPos); // current slider value glPopMatrix(); // i.e., glScalef(0.0125, 0.125, 1.0); glTranslatef(85, -5.0, 0.0); // get to start position for lettering glScalef(0.1, 0.1, 0.1); // get correct scale for lettering len= (int) strlen(label4); for (i=0; i= 360)? theta1[0]-360 : theta1[0]; theta1[1] += w1[1]; theta1[1] = (theta1[1] >= 360)? theta1[1]-360 : theta1[1]; theta1[2] += w1[2]; theta1[2] = (theta1[2] >= 360)? theta1[2]-360 : theta1[2]; } void calculateRotationForCube2() { theta2[0] += w2[0]; theta2[0] = (theta2[0] >= 360)? theta2[0]-360 : theta2[0]; theta2[1] += w2[1]; theta2[1] = (theta2[1] >= 360)? theta2[1]-360 : theta2[1]; theta2[2] += w2[2]; theta2[2] = (theta2[2] >= 360)? theta2[2]-360 : theta2[2]; } // compute the cross product of two vectors GLfloat* crossProduct(float x1, float y1, float z1, float x2, float y2, float z2) { GLfloat *r; double d; if ((r=(GLfloat*)malloc(sizeof(GLfloat) * 3)) == NULL) { perror("Memory allocation failed -- Chen Li"); exit(1); } // CrossProduct of ([x1, y1, z1], [x2, y2, z2]) = // [y1 z2 - z1 y2, z1 x2 - x1 z2, x1 y2 - y1 x2] r[0] = y1*z2 - z1*y2; r[1] = z1*x2 - x1*z2; r[2] = x1*y2 - y1*x2; // normalize it d = sqrt((double)(r[0]*r[0] + r[1]*r[1] + r[2]*r[2])); r[0] /= d; r[1] /= d; r[2] /= d; return(r); } // compute the dot product of two vectors float dotProduct(float x1, float y1, float z1, float x2, float y2, float z2) { return (x1*x2 + y1*y2 + z1*z2); } // compute the length of a vector float lengthOfVector(float x, float y, float z) { return sqrt(x*x+y*y+z*z); } // compute the angle between two vectors float getAngle(float x1, float y1, float z1, float x2, float y2, float z2) { float cos; cos = dotProduct(x1, y1, z1, x2, y2, z2) / (lengthOfVector(x1, y1, z1) * lengthOfVector(x2, y2, z2)); // printf("cos(theta) is %f, acos is %f \n", cos, acos(cos)); return(acos(cos)*360/(2*3.1415926)); // convert to degrees }