/***********************************************************************\ ** ** ** SQUEL : squelette complet de programme OpenGL + GLUT ** ** ** ** Fabrice NEYRET - janvier 2000 - copyright iMAGIS ** ** ** \***********************************************************************/ /* cc squel.c -o squel -lglut -lGLU -lGL -lXmu -lX11 -lm */ #include #include /* #include déjà dans glut.h */ /* #include déjà dans glut.h */ #include #include int SIZEX,SIZEY; /* taille de la fenêtre */ double Cdist = 10.; /* orientation de la caméra */ double Cphi = 0.; double Ctheta = 0.; double Lphi = 1.; /* orientation de la lampe */ double Ltheta = 0.; GLfloat diffuse_color[4] = { 1.5, 1.5, 1.5, 1.}; GLfloat light_pos[4] = { 0., 0., 1., 0.}; /* à l'infini */ int objet = 0; /* orientation des objets */ #define NB_OBJ 3 double Ophi [NB_OBJ] = {0., 0., 0.}; double Otheta[NB_OBJ] = {0., 0., 0.}; float scale = 3.; int ANIM=1; float temps=0.; /* pour l'animation */ /*************** interface (ligne commande, clavier, souris, menus) */ void reshape(int x,int y) { /* la taille de la fenetre change */ SIZEX=x; SIZEY=y; glViewport(0,0,SIZEX,SIZEY); } /* ----- analyse de la ligne de commande */ void parse_args(int argc, char **argv) { void change_cur_objet(int obj); printf( "\n" " commande: \n" " %s [-h] [-a] [-o NN] \n" " -a: anim off \n" " -o: bouger objet NN \n" " touches: \n" " ESC,q: quit o: change objet courant \n" " souris: \n" " LEFT: rot camera MIDDLE: dist camera \n" " SH-LEFT: rot lum CTRL-LEFT: rot objet \n" ,argv[0]); argc--; argv++; while (argc && (*argv)[0]=='-') { switch((*argv)[1]) { case 'h': exit(0); case 'a': ANIM = 0; break; case 'o': argc--; argv++; sscanf(*argv,"%d",&objet); objet--; change_cur_objet(objet); break; } argc--; argv++; } } /* ----- gestion des touches du clavier */ void key(unsigned char c,int x,int y) { void change_cur_objet(int obj); switch (c) { case 27: case 'q': exit (0); case 'o': change_cur_objet(objet+1); break; case 'a': ANIM = 1-ANIM; break; } glutPostRedisplay(); } /* ----- gestion de la souris */ struct { /* memoire des evenements souris + modifieurs */ float x ,y, /* position souris normalisee */ x0,y0, /* position precedente */ dx,dy; /* mouvement */ int left,middle,right; /* etat des boutons de la souris */ int shift,ctrl,alt; /* etat des modifieurs du clavier */ int state; /* etat global (cf flags dessous) */ } mouse; #define SHIFT 0x0001 #define CTRL 0x0002 #define ALT 0x0004 #define LEFT 0x0010 #define MIDDLE 0x0020 #define RIGHT 0x0040 void mouse_motion(int x,int y) { /* mouvement de la souris */ float xx = mouse.x, yy = mouse.y; mouse.x = x /(float)SIZEX; mouse.y = (SIZEY-y)/(float)SIZEY; mouse.dx = mouse.x-xx; mouse.dy = mouse.y-yy; switch(mouse.state) { case LEFT: Cphi += mouse.dx; Ctheta += mouse.dy; break; case SHIFT|LEFT: Lphi += mouse.dx; Ltheta += mouse.dy; break; case CTRL|LEFT: Ophi[objet] += mouse.dx; Otheta[objet] += mouse.dy; break; case MIDDLE: Cdist *= 1+mouse.dy; break; } glutPostRedisplay(); } void mouse_click(int button,int state,int x,int y) { /* clic de souris */ int alt; /* on stocke dans 'mouse' l'etat de tous les modifieurs */ switch(button) { case GLUT_LEFT_BUTTON: mouse.left = (state==GLUT_DOWN); break; case GLUT_MIDDLE_BUTTON: mouse.middle = (state==GLUT_DOWN); break; case GLUT_RIGHT_BUTTON: mouse.right = (state==GLUT_DOWN); break; } alt = glutGetModifiers(); mouse.shift = (alt&GLUT_ACTIVE_SHIFT) ?1:0; mouse.ctrl = (alt&GLUT_ACTIVE_CTRL) ?1:0; mouse.alt = (alt&GLUT_ACTIVE_ALT) ?1:0; mouse.state = SHIFT*mouse.shift | CTRL*mouse.ctrl | ALT*mouse.alt | LEFT*mouse.left | MIDDLE*mouse.middle | RIGHT*mouse.right; mouse.x0 = x /(float)SIZEX; mouse.x=mouse.x0; mouse.dx=0; mouse.y0 = (SIZEY-y)/(float)SIZEY; mouse.y=mouse.y0; mouse.dy=0; } /* ----- gestion des menus */ void change_cur_objet(int obj) { static char label[64]; objet = obj % NB_OBJ; sprintf(label,"bouger objet %d",1+(objet+1)%3); glutChangeToMenuEntry(1,label,1); } void menu(int v) { /* clic dans un menu */ switch (v) { case 1: change_cur_objet(objet+1); break; case 2: ANIM = 1-ANIM; break; case 99: exit(0); } glutPostRedisplay(); } void init_interface() { /* initialisation des menus */ glutCreateMenu(menu); glutAddMenuEntry("", 1); change_cur_objet(objet); glutAddMenuEntry("anim ON/OFF", 2); glutAddMenuEntry("Quitter" ,99); glutAttachMenu(GLUT_RIGHT_BUTTON); } /*************** affichage ******************************************/ /* description géométrique de l'objet 3 (pyramide). Ici, on a choisi de mettre des normales aux faces et non aux sommets (i.e. objet volontairement polyèdrique, et non pas lisse), et des couleurs aux sommets et non pas aux faces (i.e. interpolées le long des faces). */ #define SQRT2 1.4142138 /* sqrt(2) */ #define SQRT3S2 .8660254 /* sqrt(3)/2 */ #define nb_faces 4 float coords[nb_faces][3] = { { 0, SQRT2, 0}, {-SQRT3S2,0,-.5}, { SQRT3S2,0,-.5}, { 0 ,0, 1.} }; float colors[nb_faces][3] = { {.4,.4,.4},{1,0,0},{0,1,0},{0,0,1} }; int faces[nb_faces][3] = { {0,1,2}, {0,2,3}, {0,3,1}, {3,2,1} }; float normals[nb_faces][3] = { { 0, 1/3., -2*SQRT2/3}, { SQRT2/3, 1/3., SQRT3S2*SQRT2/3}, {-SQRT2/3, 1/3., SQRT3S2*SQRT2/3}, { 0, -1., 0} }; void draw_scene() { /* tracé de la scène */ int i; glPushMatrix(); glTranslatef(-4.,0.,0.); glRotatef(Otheta[0]*180/M_PI, 1., 0., 0.); /* on oriente l'objet 1 */ glRotatef( Ophi[0]*180/M_PI, 0., 1., 0.); glColor3f(1.,.5,.5); glutSolidTorus(1.0,2.0,20,30); glPopMatrix(); glPushMatrix(); glTranslatef(4.,0.,0.); glRotatef(Otheta[1]*180/M_PI, 1., 0., 0.); /* on oriente l'objet 2 */ glRotatef( Ophi[1]*180/M_PI, 0., 1., 0.); glColor3f(.5,.5,1.); glutSolidCube(3.); glPopMatrix(); glPushMatrix(); glTranslatef(0.,0.,-3.); glRotatef(Otheta[2]*180/M_PI, 1., 0., 0.); /* on oriente l'objet 3 */ glRotatef( Ophi[2]*180/M_PI, 0., 1., 0.); glScalef(scale,scale,scale); glBegin(GL_TRIANGLES); for(i=0; i