#include #include #include #include "glut.h" #define CUBE_SIZE 1.0 #define PI 3.1415 #define WIRE_FRAME 0 #define POLYGON 1 #define SMOOTH 1.0 #define FLAT 2.0 #define TRUE 1.0 #define FALSE 0.0 #define Rotate_Speed_Fast 6.0 #define Rotate_Speed_Normal 2.0 static float scal = 1.0; static float alpha, beta; static float incrx = 0.; static float incry = 0.; static float a,b; static float ca,cb; static float step =6.4; static int mykey = 0; static int swap =FALSE; static int animate =FALSE; static int pause =FALSE; static int final =180; static float coor_axes = 0; static float mx,my,mz; static float variation =0; static float speed =0.1; unsigned char mychar; static int surface = WIRE_FRAME; static int on = 0; /* non printable characters are better identified through defines like this */ #define ESCKEY 27 #define GLUT_KEY_LEFT 100 #define GLUT_KEY_UP 101 #define GLUT_KEY_RIGHT 102 #define GLUT_KEY_DOWN 103 #define GLUT_KEY_PAGE_UP 104 #define GLUT_KEY_PAGE_DOWN 105 #define GLUT_KEY_HOME 106 #define GLUT_KEY_END 107 #define GLUT_KEY_INSERT 108 static float light_pos[] = { 1.0, 1.0, -100, 0.0 }; static float light_pos1[] = {-1.0,-1.0, 100,0.0}; static float light_diffuse[] = { 1.0, 1.0, 1.0, 1.0}; static float light_ambient[] = { 0.5, 0.5, 0.5, 0.5}; static float light_specular[] = { 1.0, 1.0, 1.0, 1.0}; static float mat_red_diffuse[] = { 0.8, 0.1, 0.1, 1.0 }; /*Light color changing*/ static float mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; static float mat_shininess[] = { 40.0 }; void draw_axis(void); void display(void); void light_off(void); void light_on(void); void calNormal(float *px,float *py,float *pz,float px1,float py1,float pz1,float ma,float mb); int (*FirstSurface)(float *,float *,float *,float ,float); int (*FirstNormal)(float *,float *,float *,float ,float); int (*SecondSurface)(float *,float *,float *,float ,float); int (*SecondNormal)(float *,float *,float *,float ,float); /********************************************************************** This function is called only once in the very beginning. It can initialize whatever is desired. Right now, two angles are defined. ***********************************************************************/ static void Init() { alpha=-20.0; beta=20.0; glLightfv(GL_LIGHT0,GL_POSITION,light_pos); glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient); glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse); glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular); glLightfv(GL_LIGHT1,GL_POSITION,light_pos1); glLightfv(GL_LIGHT1,GL_AMBIENT,light_ambient); glLightfv(GL_LIGHT1,GL_DIFFUSE,light_diffuse); glLightfv(GL_LIGHT1,GL_SPECULAR,light_specular); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_red_diffuse); /*glEnable(GL_LIGHTING);*/ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glEnable(GL_DEPTH_TEST); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); } /********************************************************************** Formulas of different Surfaces ***********************************************************************/ /* Basic equation of the Sphere */ void f0( float *px, float *py, float *pz,float ma,float mb){ *px = cos(ma); /*Sphere*/ *py = cos(mb)*sin(ma); *pz = sin(mb)*sin(ma); } /* Calculation of the NORMAL of the Sphere */ void f00( float *px, float *py, float *pz,float ma,float mb){ static float px1,py1,pz1; /*Sphere*/ /* to get the U and V to calculate the normal*/ /*vector V*/ /*vector U*/ *px = -sin(ma); px1 = 0; *py = cos(mb)*cos(ma); py1 = sin(ma)*(-sin(mb)); *pz = sin(mb)*cos(ma); pz1 = sin(ma)*cos(mb); calNormal(&*px,&*py,&*pz,px1,py1,pz1,ma,mb); } /* Basic equation of the Shape No2 */ void f1( float *px, float *py, float *pz,float ma,float mb) { *px=(ma*cos(mb))/(2*PI); *py=(ma*sin(mb))/(2*PI); *pz=(ma*sin(mb)*sin(ma))/(2*PI); } /* Calculation of the NORMAL of the Shape No2 */ int f11( float *px, float *py, float *pz,float ma,float mb) { static float px1,py1,pz1; /* V vector */ *px=cos(mb)/(2*PI); *py=sin(mb)/(2*PI); *pz=((ma*sin(mb)*cos(ma)) + (sin(mb)*sin(ma)))/(2*PI); /* U vector */ px1=-(ma*sin(mb))/(2*PI); py1=(ma*cos(mb))/(2*PI); pz1=(ma*cos(mb)*sin(ma))/(2*PI); calNormal(&*px,&*py,&*pz,px1,py1,pz1,ma,mb); /*return 2;*/ } /* Basic equation of the Shape No10 */ void f2( float *px, float *py, float *pz,float ma,float mb) { *px=0.5*((ma-0.5*sin(ma))-3); *py=0.5*cos(mb)*(1-0.5*cos(ma)); *pz=0.5*sin(mb)*(1-0.5*cos(ma)); } /* Calculation of the NORMAL of the Shape No10 */ void f22( float *px, float *py, float *pz,float ma,float mb){ static float px1,py1,pz1; /* V vector */ *px=0.5-(0.25*cos(ma)); *py=0.25*cos(mb)*sin(ma); *pz=0.25*sin(mb)*sin(ma); /* U vector */ px1=0; py1=-(0.5*cos(mb)) + (0.25*sin(mb)*cos(ma)); pz1=(0.5*cos(mb)) - (0.25*cos(mb)*cos(ma)); calNormal(&*px,&*py,&*pz,px1,py1,pz1,ma,mb); } void calNormal(float *px,float *py,float *pz,float px1,float py1,float pz1,float ma,float mb){ static float l,h,i,j; h = ((*py)*(pz1)) - ((py1)*(*pz)); /*to get vector i*/ i = ((px1)*(*pz)) - ((*px)*(pz1)); /*to get vector j*/ j = ((*px)*(py1)) - ((px1)*(*py)); /*to get vector k*/ l = sqrt((h*h) + (i*i) + (j*j)); /* normalised vector */ *px = h/l; *py = i/l; *pz = j/l; } /*********************************************************************** Main Selection Function. It is used to select different kind of surfaces available. ************************************************************************/ void select_surfaces ( float *px, float *py, float *pz,float ma,float mb){ static float px1,py1,pz1; switch(mykey){ case 0 : final =180; f0(&*px,&*py,&*pz,ma,mb); f1(&px1,&py1,&pz1,ma,mb); f2(&px1,&py1,&pz1,ma,mb); break; case 1 : final =360.0; f1(&*px,&*py,&*pz,ma,mb); f2(&px1,&py1,&pz1,ma,mb); break; case 2 : final =360.0; f2(&*px,&*py,&*pz,ma,mb); f1(&px1,&py1,&pz1,ma,mb); break; default : printf("\nNo selection number found....."); printf("\nKEY is %d\n\n",mykey); mykey=0; break; } if(animate==TRUE){ *px = (1.0 -variation)*(*px)+variation*(px1); *py = (1.0 -variation)*(*py)+variation*(py1); *pz = (1.0 -variation)*(*pz)+variation*(pz1); } } void cn( float *px, float *py, float *pz,float ma,float mb){ static float px1,py1,pz1; switch(mykey){ case 0 : final = 180.0; f00(&*px,&*py,&*pz,ma,mb); f22(&px1,&py1,&pz1,ma,mb); break; case 1 : final =360.0; f11(&*px,&*py,&*pz,ma,mb); f22(&px1,&py1,&pz1,ma,mb); break; case 2 : final = 360.0; f22(&*px,&*py,&*pz,ma,mb); f11(&px1,&py1,&pz1,ma,mb); break; default : printf("\nNo selection number found....."); printf("\nKEY is %d\n\n",mykey); mykey=0; break; } if(animate==TRUE){ *px = (1.0 -variation)*(*px)+variation*(px1); *py = (1.0 -variation)*(*py)+variation*(py1); *pz = (1.0 -variation)*(*pz)+variation*(pz1); } } /********************************************************************** This function defines the object(s) to be drawn. Now, for wire-frame drawing, only polylines and lines are used. While drawing shaded polygons, do not forget to define materials and lights in Init() ***********************************************************************/ MakeObject( void ) { if(surface==WIRE_FRAME){ draw_axis(); glColor3f(0.0, 1.0, 0.0); for(ca=0.0;ca<=final+step;ca+=step+4.0){ glBegin(GL_LINE_STRIP); for(cb=0.0;cb<=360.0+step;cb+=step+4.0){ select_surfaces (&mx,&my,&mz,(ca*PI)/180,(cb*PI)/180); glVertex3f(mx,my,mz); } glEnd(); } for(cb=0.0;cb<=final+step;cb+=step+4.0){ glBegin(GL_LINE_STRIP); for(ca=0.0;ca<=360.0+step;ca+=step+4.0){ select_surfaces (&mx,&my,&mz,(ca*PI)/180,(cb*PI)/180); glVertex3f(mx,my,mz); } glEnd(); } } else { light_off(); draw_axis(); light_on(); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL) ; if (surface == FLAT) glShadeModel (GL_FLAT); else if (surface == SMOOTH) glShadeModel (GL_SMOOTH) ; if ((surface == FLAT) || (surface == SMOOTH)) final = 360; else final = 180; for(ca=0.0;ca<=final;ca+=step) { glBegin(GL_QUAD_STRIP); for(cb=0.0;cb<=360.0;cb+=step) { glColor3f(0.0, 0.0, 1.0); /*Set color to Red*/ cn(&mx,&my,&mz,(ca*PI/180),(cb*PI/180)); glNormal3f(mx,my,mz); select_surfaces (&mx,&my,&mz,(ca*PI/180),(cb*PI/180)); glVertex3f(mx,my,mz); cn(&mx,&my,&mz,(ca*PI/180)+step/18,(cb*PI/180)); glNormal3f(mx,my,mz); select_surfaces (&mx,&my,&mz,(ca*PI/180)+step/18,(cb*PI/180)); glVertex3f(mx,my,mz); cn(&mx,&my,&mz,(ca*PI/180),(cb*PI/180)+step/18); glNormal3f(mx,my,mz); select_surfaces (&mx,&my,&mz,(ca*PI/180),(cb*PI/180)+step/18); glVertex3f(mx,my,mz); cn(&mx,&my,&mz,(ca*PI/180)+step/18,(cb*PI/180)+step/18); glNormal3f(mx,my,mz); select_surfaces (&mx,&my,&mz,(ca*PI/180)+step/18,(cb*PI/180)+step/18); glVertex3f(mx,my,mz); } glEnd(); } for(cb=0.0;cb<=final;cb+=step) { glBegin(GL_QUAD_STRIP); for(ca=0.0;ca<=360.0;ca+=step) { glColor3f(0.0, 0.0, 1.0); /*Set color to Red*/ cn(&mx,&my,&mz,(ca*PI/180),(cb*PI/180)); glNormal3f(mx,my,mz); select_surfaces (&mx,&my,&mz,(ca*PI/180),(cb*PI/180)); glVertex3f(mx,my,mz); cn(&mx,&my,&mz,(ca*PI/180)+step/18,(cb*PI/180)); glNormal3f(mx,my,mz); select_surfaces (&mx,&my,&mz,(ca*PI/180)+step/18,(cb*PI/180)); glVertex3f(mx,my,mz); cn(&mx,&my,&mz,(ca*PI/180),(cb*PI/180)+step/18); glNormal3f(mx,my,mz); select_surfaces (&mx,&my,&mz,(ca*PI/180),(cb*PI/180)+step/18); glVertex3f(mx,my,mz); cn(&mx,&my,&mz,(ca*PI/180)+step/18,(cb*PI/180)+step/18); glNormal3f(mx,my,mz); select_surfaces (&mx,&my,&mz,(ca*PI/180)+step/18,(cb*PI/180)+step/18); glVertex3f(mx,my,mz); } glEnd(); } } if(animate==TRUE){ if(swap==FALSE){ if(pause == FALSE) variation += 0.1*speed; if(variation>=1.0){ swap=1; } } else{ if(pause == FALSE) variation -= 0.1*speed; if(variation<=0.0){ swap=0; } } } } void draw_axis(){ if(coor_axes==0){ /* Set color to red - X AXIS */ glColor3f(1.0, 0.0, 0.0); /* Coordinate axes - three lines */ glBegin(GL_LINES); /* CL_LINES defines segments of straight line connecting vertices v1 with v2, v3 with v4, v5 with v6, etc. */ glVertex3f(-2.0*CUBE_SIZE,0,0); glVertex3f(2.0*CUBE_SIZE,0,0); glEnd(); /* Set color to green Y AXIS*/ glColor3f(0.0, 1.0, 0.0); glBegin(GL_LINES); glVertex3f(0,-2.0*CUBE_SIZE,0); glVertex3f(0,2.0*CUBE_SIZE,0); glEnd(); /* Set color to blue Z AXIS*/ glColor3f(0.0, 0.0, 1.0); glBegin(GL_LINES); glVertex3f(0,0,-2.0*CUBE_SIZE); glVertex3f(0,0,2.0*CUBE_SIZE); glEnd(); } } /*********************************************************************** Main Drawing Function. It is called by the system to draw every next buffer with the maximum speed available. ************************************************************************/ static void Draw( void ) { glClearColor (0.3, 0.0, 0.5, 0.0); glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT); glPushMatrix(); alpha=alpha+incrx; beta=beta+incry; if (alpha>360.0) alpha=0.0; if (beta>360.0) beta=0.0; if (alpha<0.0) alpha=360.0; if (beta <0.0) beta=360.0; /* This translation is done for the visualization transformation */ glTranslatef(0.0,0.0,-5*CUBE_SIZE); /* The following are rotations done about Y followed by rotation about X */ glRotatef(beta, 1.0, 0.0, 0.0); glRotatef(alpha, 0.0, 1.0, 0.0); /* This could be a scaling if you decide to scale. Right now we scale by 1,1,1 */ glScalef(scal,scal,scal); /* Here, the MakeObject function is called. You have to change it first to draw the requested objects */ MakeObject(); /* glFlush(); --> not used in GLUT */ glPopMatrix(); glutSwapBuffers(); } /****************************************************************** Key-Pressed events handling *******************************************************************/ void Close(void) { exit(0); } static void Rotate(void) { /* Toggle between rotation and stop rotation */ static float LastRotation = 1.; if (incrx >0.) { LastRotation = incrx; /* we save inc because it will have */ incrx = 0.; /* different values later on */ } else{ if(surface!=WIRE_FRAME) LastRotation=Rotate_Speed_Fast; else LastRotation=Rotate_Speed_Normal; incrx = LastRotation; } } static void Rotate_Left(void) { /* Toggle between rotation and stop rotation */ incrx=0; incry=0; alpha=alpha-3; } static void Rotate_Right(void) { /* Toggle between rotation and stop rotation */ incrx=0; incry=0; alpha=alpha+3; } static void Rotate_Up(void){ incrx=0; incry=0; beta=beta-3; } static void Rotate_Down(void){ incrx=0; incry=0; beta=beta+3; } static void Shrink(void){ if(scal>0) scal -=0.1; } static void Enlarge(void){ scal +=0.1; } static void axes(void){ static float remb_coor_axes = 1; if(coor_axes>0){ remb_coor_axes=coor_axes; coor_axes=0; } else coor_axes=remb_coor_axes; } static void quality_Inc(void){ step -=0.5; } static void quality_Dec(void){ step +=0.5; } static void wire_frame(){ surface=WIRE_FRAME; animate=FALSE; light_off(); } static void smooth(){ surface=SMOOTH; } static void flat(){ surface=FLAT; } static void animation(){ static float ani = 1; if(animate == TRUE){ ani=animate; animate=FALSE; speed=0.2; } else{ animate=ani; variation=0; } } static void fast_animation(void){ if(animate==TRUE){ speed +=0.1; if(speed >4.0){ speed=4.0; } } } static void slow_animation(void){ if(animate==TRUE){ speed -=0.1; if(speed <0.1){ speed=0.1; } } } static void pause_animation(void){ static float a = 1; if(pause == TRUE){ a=pause; pause=FALSE; } else { pause=a; } } void light_off(void){ glDisable(GL_LIGHTING); } void light_on(void){ glEnable(GL_LIGHTING); } void brighter(void) { /* Toggle between rotation and stop rotation */ static float brighter= 1.; if (on >0.) { brighter = on; on = 0; glDisable(GL_LIGHT1); } else { on = brighter; glEnable(GL_LIGHT1); } } /****************************************************************** In this function the projection transformation is defined. Currently, it is perspective projection. It can be orthographic projection as well if one uses the commented glOrtho instead of glFrustum *******************************************************************/ void Reshape(GLsizei w, GLsizei h) { glMatrixMode (GL_PROJECTION); glLoadIdentity (); /* This glOrtho can be used in place of glFrustrum if perspective projection is not desired.*/ /* glOrtho(-2.0*CUBE_SIZE, 2.0*CUBE_SIZE, -2.0*CUBE_SIZE, 2.0*CUBE_SIZE, 0.0*CUBE_SIZE, 10.0*CUBE_SIZE);*/ glFrustum(-2.0*CUBE_SIZE, 2.0*CUBE_SIZE, -2.0*CUBE_SIZE, 2.0*CUBE_SIZE, 3.0*CUBE_SIZE, 40.0*CUBE_SIZE); glMatrixMode(GL_MODELVIEW); glViewport(0, 0, w, h); } void Reshape1(GLsizei w, GLsizei h) { float aspect; glMatrixMode (GL_PROJECTION); glLoadIdentity (); aspect = (float) w/h; gluPerspective(70.0, aspect,0.1 , 10); glMatrixMode(GL_MODELVIEW); glViewport(0, 0, w, h); } /****************************************************************** This function calls Draw if there is nothing else to call *******************************************************************/ static void Idle(void) { glutPostRedisplay(); /* forces the redisplay to produce the animation */ } /****************************************************************** This function deals with non printable characters key strokes (ESC, ...) *******************************************************************/ static void special(int c, int x, int y) { mykey=((int) c )-48; switch (c) { case ESCKEY : Close(); break; }/* end switch() */ } static void SpFunc(int key, int x, int y){ switch (key) { case GLUT_KEY_UP : Rotate_Up(); break; case GLUT_KEY_DOWN : Rotate_Down(); break; case GLUT_KEY_LEFT : Rotate_Left(); break; case GLUT_KEY_RIGHT : Rotate_Right(); break; default : printf("\nNot a Special Key..."); break; } } /****************************************************************** This function intercepts all key strokes and deals with normal characters *******************************************************************/ static void keyboard(unsigned char c, int x, int y) { mychar = c; switch (c) { case 'r' : case 'R' : Rotate(); /* 'R' or 'r' keystroke starts/stops rotation */ break; case 'z' : Shrink(); break; case 'Z' : Enlarge(); break; case 'm' : Rotate_Up(); break; case 'n' : Rotate_Down(); break; case 'x' : case 'X' : axes(); break; case 'q' : quality_Dec(); break; case 'Q' : quality_Inc(); break; case 'P' : smooth(); break; case 'p' : flat(); break; case 'w' : case 'W' : wire_frame(); break; case 'a' : case 'A' : animation(); break; case 'F' : case 'f' : fast_animation(); break; case 'S' : case 's' : slow_animation(); break; case 'T' : case 't' : pause_animation(); break; case 'o' : case 'O' : brighter(); break; default: special(c,x,y); /* it's perhaps a non printable character */ break; } } void display(void){ printf("\n\n\tDone By : Liew Wee Teck\n"); printf("\tGroup : ST2\n"); printf("\tSc208 - Programming of Graphics With OpenGL(GLUT)\n"); printf("\n\tMain Menu(please use the below choices)\n"); printf("\n\tPress num <0> : Display Sphere"); printf("\n\tPress num <1> : Display 1st Surface(no2)"); printf("\n\tPress num <2> : Display 2nd Surface(no10)"); printf("\n\tPress : Rotate Left"); printf("\n\tPress : Rotate Right"); printf("\n\tPress : Rotate Up"); printf("\n\tPress : Rotate Down"); printf("\n\tPress or : Start/Stop Animation"); printf("\n\tPress or : Fast Animation"); printf("\n\tPress

: Smooth Shading"); printf("\n\tPress

: Flat Shading"); printf("\n\tPress : Increase Rendering Quality"); printf("\n\tPress : Decrease Rendering Quality"); printf("\n\tPress or : Start/Stop Rotation"); printf("\n\tPress or : Slow Animation"); printf("\n\tPress or : Pause/Resume Animation"); printf("\n\tPress or : Wire Frame Mode"); printf("\n\tPress or : View/Hide Coodinate Axes"); printf("\n\tPress : Zooming In"); printf("\n\tPress : Zooming Out"); printf("\n\tPress ESC \t : Quit\n\t"); } /****************************************************************** This is the main function. It defines the display modes, the initial window position and its size. It also defines the functions for Display, Reshape and for intercepting key strokes in the keyboard. *******************************************************************/ void main( int argc, char *argv[] ) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB); glutCreateWindow("Done By : Liew Wee Teck Group : ST2"); glutReshapeWindow(1200,600); display(); glutDisplayFunc(Draw); glutReshapeFunc(Reshape1); glutKeyboardFunc(keyboard); glutSpecialFunc(SpFunc); glutIdleFunc(Idle); Init(); glutMainLoop(); }