sp.cpp

00001 // Démonstration du mécanisme de sélection et picking
00006 // la souris (bouton gauche) permet de faire tourner toute la scène
00007 //
00008 // Clic droit sur un des points pour le sélectionner et l'afficher en jaune
00009 // Echap pour quitter l'application
00010 
00011 #include <iostream>
00012 #include <stdlib.h>
00013 #include <GL/glut.h>
00014 
00015 using namespace std;
00016 
00017 class Scene{
00018 public:
00019   GLfloat spinG_x, spinG_y; //Rotation globale de la scène
00020   GLint selected;           //Nom du point sélectionné
00021   int mouse_x, mouse_y;     //Sauvegarde des coordonnées de la souris
00022   int mode_selection;       //Est-on en mode sélection ?
00023   GLfloat x0,y0,z0,x1,y1,z1;//Coordonnées de deux points P0 et P1
00024 
00025   Scene(){
00026     spinG_x = spinG_y = 0;
00027     selected = -1;
00028     x0 = y0 = z0 = -2;
00029     x1 = y1 = z1 = 2;
00030     mode_selection = false;
00031   }
00032   void Init(){
00033     //On épaissit les points
00034     glPointSize(10);
00035     //On épaissit les lignes
00036     glLineWidth(2.0);
00037   }
00038   void setProjection(){
00039     glOrtho(-5, 5, -5, 5, -5, 5);
00040   }
00041   void Draw(GLenum mode);
00042 
00043   ~Scene(){};
00044 };
00045 
00046 
00047 //Affiche la scène pour l'affichage ou pour le picking
00048 void Scene::Draw(GLenum mode)
00049 { 
00050   glPushMatrix();
00051   {
00052     //On contrôle à la souris la rotation globale de la scène
00053     glRotatef(spinG_y, 1, 0, 0);
00054     glRotatef(spinG_x, 0, 1, 0);
00055     
00056     
00057     if (mode == GL_RENDER)
00058       {
00059         //Segment de droite blanc
00060         glColor3f(1, 1, 1);
00061         glBegin(GL_LINES);
00062         glVertex3f(x0, y0, z0);
00063         glVertex3f(x1, y1, z1);
00064         glEnd();
00065         
00066         //Deux points bleutés ou jaunes s'ils sont sélectionnés
00067         glBegin(GL_POINTS);
00068         if (selected == 1)
00069           glColor3f(1, 1, 0);  
00070         else
00071           glColor3f(0, 0, .8);  
00072         glVertex3f(x0, y0, z0);
00073 
00074         if (selected == 2)
00075           glColor3f(1, 1, 0);  
00076         else
00077           glColor3f(0, 0, .8);  
00078         glVertex3f(x1, y1, z1);
00079         glEnd();
00080 
00081         glColor3f(0, 0, .8);  
00082       }
00083     else //mode GL_SELECT
00084       {
00085         //ATTENTION, on ne peut pas mettre le glLoadName ENTRE glBegin et glEnd !
00086 
00087         //Deux points avec leurs noms
00088         glLoadName(1);
00089         glBegin(GL_POINTS);
00090         glVertex3f(x0, y0, z0);
00091         glEnd();
00092 
00093         glLoadName(2);
00094         glBegin(GL_POINTS);
00095         glVertex3f(x1, y1, z1);
00096         glEnd();
00097     }
00098   }
00099   glPopMatrix();
00100 
00101 } //Draw()
00102 
00103 
00104 Scene s;
00105 
00106 
00107 //Pour redimensionner la fenêtre
00108 void myReshapeFunc(int w,int h)
00109 {
00110   glViewport(0,0,(GLint) w,(GLint) h);
00111 
00112   glMatrixMode( GL_PROJECTION );
00113   glLoadIdentity();
00114   
00115   s.setProjection();
00116   
00117   glMatrixMode( GL_MODELVIEW );
00118 }//myReshapeFunc()
00119  
00120 
00121 //Fonction d'affichage
00122 void myDisplayFunc()
00123 {
00124   // Nettoyage du "Tampon Chromatique" et du "Z buffer" 
00125   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00126 
00127   //On dessine la scène
00128   s.Draw(GL_RENDER);
00129   
00130   // Permute les "back buffer" et "front buffer" (double-buffering).
00131   glutSwapBuffers();
00132   
00133 }//myDisplayFunc()
00134 
00135  
00136 //traitement du buffer de picking
00137 void processHits (GLint hits, GLuint buffer[])
00138 {
00139   GLuint i, nb_names, name, *ptr;
00140   GLdouble z1, z2;
00141 
00142   //on réinitialise la sélection
00143   s.selected = -1;
00144 
00145   //S'il y a plusieurs hits, il faudrait choisir le nom de l'objet le plus proche
00146   //  et non pas celui du dernier hit comme ici.
00147   printf ("hits = %d\n", hits);
00148   ptr = (GLuint *) buffer;
00149   for (i = 0; i < hits; i++) {  /*  for each hit  */
00150     nb_names = ptr[0];
00151     if (nb_names != 1) {
00152       cerr << "erreur, ce programme ne supporte qu'un seul nom dans la pile, et non pas " << nb_names << endl;
00153       exit(1);
00154     }
00155     
00156     z1 = (double) ptr[1]/0x7fffffff;
00157     z2 = (double) ptr[2]/0x7fffffff;
00158     cout << "zmin = " << z1 << ", zmax= " << z2 << endl;
00159     
00160     name = ptr[3];
00161     s.selected = name;
00162     cout << "selected = " << s.selected << endl;
00163   }
00164 }
00165 
00166 #define BUFSIZE 512
00167 
00168 //Pour sélectionner un objet dans la scène
00169 void myPick(int x, int y){
00170   GLuint selectBuf[BUFSIZE];
00171   GLint hits;
00172   GLint viewport[4];
00173 
00174   //on récupère le viewport courant
00175   glGetIntegerv(GL_VIEWPORT, viewport);
00176   
00177   glSelectBuffer(BUFSIZE, selectBuf);
00178   (void) glRenderMode(GL_SELECT);
00179   
00180   //Initialisation de la pile des noms
00181   glInitNames();
00182   glPushName(0);
00183   
00184   glMatrixMode(GL_PROJECTION);
00185   glPushMatrix();
00186   glLoadIdentity();
00187   /*  create 10x10 pixel picking region near cursor location    */
00188   gluPickMatrix((GLdouble) x, (GLdouble) (viewport[3] - y), 
00189                  10.0, 10.0, viewport);
00190   //On doit avoir la même projection en mode sélection qu'en mode rendu :
00191   s.setProjection();
00192   glMatrixMode(GL_MODELVIEW);
00193 
00194   //On calcule la scène pour le picking : elle n'est pas dessinée dans un tampon chromatique
00195   s.Draw(GL_SELECT);
00196   
00197   glMatrixMode(GL_PROJECTION);
00198   glPopMatrix();
00199   glMatrixMode(GL_MODELVIEW);
00200 
00201   //On s'assure que les ordre OpenGL sont exécutés
00202   glFlush();
00203   
00204   hits = glRenderMode(GL_RENDER);
00205 
00206   //On traite les sommets cliqués
00207   processHits (hits, selectBuf);
00208 
00209   glutPostRedisplay(); 
00210 }
00211 
00212 void myKeyboardFunc(unsigned char k,int x,int y)  
00213 { 
00214   switch(k)  
00215     { 
00216     case 27 : exit(0);break;
00217     default: break; 
00218     }  
00219   // actualisation de l'affichage  
00220   glutPostRedisplay();
00221 
00222 }//myKeyboardFunc()
00223 
00224 //myMouseFunc
00225 void myMouseFunc(int button, int state, int x, int y) 
00226 {
00227   if ((button == GLUT_RIGHT_BUTTON)
00228       && (state == GLUT_DOWN)){
00229     //On utilise le bouton de droite pour le picking des points
00230     s.mode_selection = true;
00231     
00232     cout << "Picking" <<endl;
00233     myPick(x, y); 
00234   }
00235   
00236   if ((button == GLUT_LEFT_BUTTON)
00237       && (state == GLUT_DOWN)){
00238     s.mode_selection = false;
00239 
00240     s.mouse_x = x;
00241     s.mouse_y = y;
00242     //    cout << "mouse_x = "<< s.mouse_x << endl;
00243     //    cout << "mouse_y = "<< s.mouse_y << endl;
00244   }    
00245   glutPostRedisplay(); 
00246 }//myMouseFunc
00247   
00248 void myMotionFunc(int x, int y){
00249   if (!s.mode_selection){
00250     s.spinG_x += (s.mouse_x - x);
00251     if (s.spinG_x > 360.0) s.spinG_x -= 360.0;
00252     if (s.spinG_x < -360.0) s.spinG_x += 360.0;
00253     
00254     s.spinG_y += (s.mouse_y - y);
00255     if (s.spinG_y > 360.0) s.spinG_y -= 360.0;
00256     if (s.spinG_y < -360.0) s.spinG_y += 360.0;
00257     
00258     s.mouse_x = x;
00259     s.mouse_y = y;
00260     //    cout << "mouse_x = "<< s.mouse_x << endl;
00261     //    cout << "mouse_y = "<< s.mouse_y << endl;
00262     
00263     glutPostRedisplay();
00264   }
00265 }//myMotionFunc()
00266 
00267 
00268 void init(int argc,char** argv)
00269 { 
00270   glutInit(&argc,argv);
00271   // Paramètres du contexte de rendu.
00272   glutInitDisplayMode( GLUT_DOUBLE |GLUT_DEPTH );
00273   // Dimensions de la fenêtre.
00274   glutInitWindowSize(500, 500);
00275   // Position du coin haut-gauche de la fenêtre.
00276   glutInitWindowPosition(50,50);
00277   // Creation de la fenêtre (titre en paramètre).
00278   glutCreateWindow("Selection et Picking");
00279   // Association des fonctions utilisateurs et des 
00280   // callbacks glut (appelées lors d'un événement).
00281   glutReshapeFunc(myReshapeFunc);
00282   glutDisplayFunc(myDisplayFunc);
00283   glutKeyboardFunc(myKeyboardFunc); 
00284   glutMouseFunc(myMouseFunc);
00285   glutMotionFunc(myMotionFunc);
00286 
00287   // Couleur du fond
00288   glClearColor(.5, 0, 0, 1);
00289 
00290   // Activation du test de profondeur
00291   glEnable(GL_DEPTH_TEST);
00292         
00293   //Initialisation de la scène
00294   s.Init();
00295         
00296 }//init()
00297 
00298 int main(int argc,char **argv)
00299 {
00300   init(argc,argv);
00301   glutMainLoop();
00302   return 0;
00303 
00304 }//main()
00305 

Generated on Tue Dec 13 14:40:30 2005 by  Doxygen 1.4.5 and modified with a living human hand...