object selection problem - please help

Hello. I have a problem with object selection in a scene. I read the other posts regarding this kind of problem but I couldn’t find a clear solution.
In my application the objects are drawn in lists and the color is set with glMaterial. I have 8 lists and each of them contain 2-to-4 different objects (different colors). I’m working with Qt and initializeGL() function builds the lists. Because the objects are linked serially the paintGL() looks like this (truncated for 4 objects):


void GLWidget::paintGL() 
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |GL_STENCIL_BUFFER_BIT);
glLoadIdentity(); 
glPushMatrix();
   glCallList(baseObj);
   glPushMatrix();
      glTranslatef(0.0,0.0,410.0);
      glRotatef(z1,0,0,1);
      glCallList(link1Obj);
      glPushMatrix();
          glTranslatef(150.0,-130.0,0);
          glRotatef(z2,0,1,0);
          glCallList(link2Obj);
          glPushMatrix();
             glRotatef(z3,0,1,0);
             glCallList(link3Obj);
          glPopMatrix();
      glPopMatrix();
  glPopMatrix();
glPopMatrix();
}

From the other posts I understood that selecting objects based on the back buffer color would be recommended (if I’m not wrong). The problem is that I dont know if this is possible when using glMaterials.
Is there a way to do color based selection when using materials?
Are there other ways to pick/select objects (independent of the GPU model… I have an ATI mobility 2600) considering that my objects are quite complicated in shape?
Thank you.

P.S: this is my initializeGL:


void GLWidget::initializeGL()
{
        glMatrixMode(GL_MODELVIEW);
        glShadeModel(GL_FLAT);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glEnable (GL_DEPTH_TEST);
        glEnable (GL_NORMALIZE);
        glEnable (GL_LIGHTING);
        trajectoryObj = makeTrajectory(1);
        floorObj = makeFloor(1);
        dummyObj = makeDummy(1);
        axesObj  = makeAxes(1);
        baseObj  = makeBase(1);
        link1Obj = makeLink1(1);
        link2Obj = makeLink2(1);
        link3Obj = makeLink3(1);
        link4Obj = makeLink4(1);
        link5Obj = makeLink5(1);
        link6Obj = makeLink6(1);
        fingerObj = makeFinger(1);
  
        glEnable (GL_LIGHT0);
        glEnable (GL_LIGHT1);
        glEnable (GL_LIGHT2);

}

I use myself the classic OpenGL solution and just draw the with the GL_SELECT mode set by glRenderMode().

Full explanation here http://glprogramming.com/red/chapter13.html

I do not know if this is the best approach, but I think either way it must render the scene 2 times.

Thank you.
I tried selection using GL_SELECT but still having some problems. After the left click the whole scene is a mess… looks like its zoomed with a very high factor and also rotated. I cant bring back the objects to the screen.
This is what I used for selection (on left click):


if (event->buttons() & Qt::LeftButton) {

     GLuint selectBuf[512];
     GLint hits;
     GLint viewport[4];
     glGetIntegerv (GL_VIEWPORT, viewport);

     glSelectBuffer (512, selectBuf);
     glRenderMode (GL_SELECT);
     rendermode = GL_SELECT;
     glInitNames();
     glPushName(0);
       glMatrixMode (GL_PROJECTION); // <-- this causes a problem
       glLoadIdentity ();
       gluPickMatrix ((GLdouble) event->x(), (GLdouble) (viewport[3] - event->y()),5.0, 5.0, viewport);
       glOrtho(-3200, +3200, +2080, -2080, -8000.0,8000.0);
       selectmode(); //draw the scene
       glMatrixMode (GL_MODELVIEW);
     hits = glRenderMode (GL_RENDER);
     rendermode = GL_RENDER;
     processHits (hits, selectBuf);
 }

I took glOrtho from my redraw function which is:


void GLWidget::resizeGL(int width, int height)
{
        glViewport(0,0,800,520);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(-3200, +3200, +2080, -2080, -8000.0,8000.0);
        glMatrixMode(GL_MODELVIEW);
}

if I comment the line glMatrixMode (GL_PROJECTION) the scene is properly drawn but the select returns the whole list of objects (always the 1st object is the one with id=0).
My processHits function looks like this:


void GLWidget::processHits (GLint hits, GLuint buffer[])
{
   unsigned int i, j;
   GLuint names, *ptr;
   QString thetext;
   QMessageBox msgBox;
   thetext = QString("hits %1").arg(hits);
   msgBox.setText(thetext);
   msgBox.exec();
   ptr = (GLuint *) buffer;
   for (i = 0; i < hits; i++) { /*  for each hit  */
      names = *ptr;
      ptr++;
      ptr++;
      ptr++;
      for (j = 0; j < names; j++) {     
          thetext = QString("Name ID %1
").arg(*ptr);
          msgBox.setText(thetext);
          msgBox.exec();
          ptr++;
      }
   }
}

… and the selectmode function (which draws the scene in select mode):


void GLWidget::selectmode()
{
        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |GL_STENCIL_BUFFER_BIT);
       // glLoadIdentity();
        glClearColor(0.0f,0.2f,0.2f,0.0f);
        glDisable(GL_LIGHTING);
        //scale the scene
        glScalef(scale+1,scale+1,scale+1);
        //move scene
        glTranslatef(xmove,ymove+350,zmove);
        //rotate scene
        glRotatef(60.0, 1.0, 0.0, 0.0);
        glRotatef(30.0, 0.0, 0.0, 1.0);
        glRotatef(xRot+90, 0.0, 0.0, 1.0);
        glRotatef(yRot, 0.0, 1.0, 0.0);
        glRotatef(zRot, 1.0, 0.0, 0.0);
        //draw objects
        glPushMatrix();
        glRotatef(90, 0.0, 0.0, 1.0);
        glTranslatef(0.0,0.0,410.0);
        if(showTrajectory != 0 )
            glCallList(trajectoryObj);
        glPopMatrix();
        glCallList(floorObj);
        glPushMatrix();
            if(displayLink.at(0) != 0)
            {
               glLoadName(1);
               glCallList(baseObj);
            }
            if(displayFrame.at(0) != 0)
            {
                glPushMatrix();
                glRotatef(180, 0.0, 0.0, 1.0);
                glCallList(axesObj);
                glPopMatrix();
            }
            glPushMatrix();
                glTranslatef(0.0,0.0,410.0);
                glRotatef(z1,0,0,1);
                if(displayLink.at(1) != 0)
                {
                    glLoadName(2);
                    glCallList(link1Obj);
                }
                if(displayFrame.at(1) != 0)
                {
                    glPushMatrix();
                    glRotatef(180, 0.0, 0.0, 1.0);
                    glCallList(axesObj);
                    glPopMatrix();
                }
                glPushMatrix();
                      glTranslatef(150.0,-130.0,0);
                      glRotatef(90,0,1,0);
                      glRotatef(z2,0,1,0);
                      if(displayFrame.at(2) != 0)
                      {
                          glPushMatrix();
                          glRotatef(-90,0,1,0);
                          glTranslatef(0.0,130.0,0);
                          glRotatef(-90, 1.0, 0.0, 0.0);
                          glRotatef(-180, 0.0, 1.0, 0.0);
                          glRotatef(90, 0.0, 0.0, 1.0);
                          glCallList(axesObj);
                          glPopMatrix();
                      }
                      if(displayLink.at(2) != 0)
                      {
                          glLoadName(3);
                          glCallList(link2Obj);
                      }
                      glPushMatrix();
                        glTranslatef(-360.0,75.0,0.0);
                        glRotatef(z3,0,1,0);
                        if(displayFrame.at(3) != 0)
                        {
                            glPushMatrix();
                            glTranslatef(0.0, 55.0,0);
                            glRotatef(90, 1.0, 0.0, 0.0);
                            glCallList(axesObj);
                            glPopMatrix();
                        }
                        if(displayLink.at(3) != 0)
                        {
                            glCallList(link3Obj);
                        }
                        glPushMatrix();
                            glTranslatef(-100.0,75.0, 135);
                            glRotatef(z4,0,0,1);
                            if(displayLink.at(4) != 0)
                            glCallList(link4Obj);
                            if(displayFrame.at(4) != 0)
                                glCallList(axesObj);
                            glPushMatrix();
                                glTranslatef(0.0,0.0,295);
                                glRotatef(-z5,0,1,0);
                                if(displayLink.at(5) != 0)
                                glCallList(link5Obj);
                                if(displayFrame.at(5) != 0)
                                {
                                    glPushMatrix();
                                    glRotatef(90, 1.0, 0.0, 0.0);
                                    glCallList(axesObj);
                                    glPopMatrix();
                                }
                                glPushMatrix();
                                    glTranslatef(0.0,0.0,100);
                                    glRotatef(z6,0,0,1);
                                    if(displayLink.at(6) != 0)
                                    glCallList(link6Obj);
                                    if(displayFrame.at(6) != 0)
                                        glCallList(axesObj);
                                    glPushMatrix();
                                        glTranslatef(0.0,0.0,50);
                                        glPushMatrix();
                                                glPushMatrix();
                                                    glTranslatef(0.0,0.0,47.5);
                                                    glLoadName(4);
                                                    glCallList(dummyObj);
                                                    if(displayFrame.at(7) != 0)
                                                    {
                                                        glCallList(axesObj);
                                                     }
                                                glPopMatrix();
                                                if(gripper_status == TRUE)
                                                    gripper_stroke=27.5;
                                                else
                                                    gripper_stroke=17.5;
                                                glTranslatef(0.0,gripper_stroke,0.0);
                                                if(displayLink.at(7) != 0)
                                                glCallList(fingerObj);
                                                glTranslatef(0.0,-gripper_stroke,0.0);
                                                glRotatef(180,0,0,1);
                                                glTranslatef(0.0,gripper_stroke,0.0);
                                                if(displayLink.at(7) != 0)
                                                glCallList(fingerObj);
                                        glPopMatrix();
                                    glPopMatrix();
                                glPopMatrix();
                            glPopMatrix();
                        glPopMatrix();
                    glPopMatrix();
                glPopMatrix();
            glPopMatrix();
        glPopMatrix();
}

I’m sure I’m missing something but I cant figure out what.
I appreciate any help. Thanks

I think I solved the problem. Seems that the projection matrix was manipulated wrong. These are the modifications I made:
In mouse event:


if (event->buttons() & Qt::LeftButton) {

           GLint viewport[4];
           GLfloat proj[16];
           GLuint selectBuf[512];
           int hits;
           glGetIntegerv(GL_VIEWPORT,viewport);
           glGetFloatv(GL_PROJECTION_MATRIX, proj);//save the projection matrix

           glSelectBuffer(512,selectBuf);
           glRenderMode(GL_SELECT);
           glInitNames();
           glPushName(0);
           glMatrixMode(GL_PROJECTION);
           glLoadIdentity();
           gluPickMatrix(event->x(),viewport[3]-event->y(),1,1,viewport);
           glMultMatrixf(proj);// projection
           glMatrixMode(GL_MODELVIEW);
           selectmode();
           glMatrixMode(GL_PROJECTION);
           glFlush();
           hits = glRenderMode(GL_RENDER);
           resizeGL(0,0);
           if (hits != 0)
             processHits(hits,selectBuf);
 }

Also in the selectmode function I uncommented glLoadIdentity and loaded name 0 at the beginning. Since the objects are linked and after each list call the matrix is pushed, I used glPushName/PopName for each object. processHits is looking now only in the last hit for the last object. For example, if I click object no. 5 the names stack will contain the names 0,1,2,3,4,5…
I’m not sure if this is the best solution, but at least it works. If anyone can give me better ideas/advices I appreciate it.
Thanks