/*
 * GETSELECTEDNAME(mx, my)
 * 
 *   Input:
 *      mx - x coordinate of the mouse (or any point of interest)
 *      my - y coordinate of the mouse
 *
 *   Output: 
 *      the name of the closest object rendered at the point of interest
 */
GLint Renderer::getSelectedName(int mx, int my)
{
    GLint viewport[4], num_hits;
    GLuint select_buf[SELECT_BUF_SIZE];
    
    // Prepare the selection buffer
    glSelectBuffer(SELECT_BUF_SIZE, select_buf);
    glGetIntegerv(GL_VIEWPORT, viewport);
    
    // Enter selection mode
    glRenderMode(GL_SELECT);
    
    // Initialize name stack
    glInitNames();
    glPushName(0);
    
    // Define viewing volume based on mouse position
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();   // Save current projection matrix 
    glLoadIdentity();
    
    // A "pick" matrix uses a very small viewport to avoid rendering
    // stuff outside of the region of interest
    // SELECT_REGION_SIZE should be a small number, like 1 or 2
    gluPickMatrix((GLdouble)mx, (GLdouble)(viewport[3]-my),
                  SELECT_REGION_SIZE, SELECT_REGION_SIZE, viewport);
    gluPerspective(60.0, viewport[2]/viewport[3], 0.01, 1000.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(eye[0], eye[1], eye[2],       // Eye
	  look_at[0], look_at[1], look_at[2],   // "Look at" position
	  0.0, 1.0, 0.0 );     
    
    // Render the scene with names
    the_model->draw(OBJ_SELECT);
    
    // Exit selection mode
    num_hits = glRenderMode(GL_RENDER);
    
    // Analyze hit records
    GLuint names, *ptr;
    ptr = select_buf;
    
    int i, j;
    bool found_hit = false;
    int min_z = (1<<30), curr_z;
    vector <int> name(0), hit_name(0);
    
    // Find the closest hit
    for (i=0; i < num_hits; i++) {
      names = *ptr;     ptr++;
      curr_z = *ptr;    ptr++;
      /*discard far z*/ ptr++;
      name.resize(names);
      for (j=0; j < names; j++) {
        name[j] = *ptr;
        ptr++;
      }
      
      if (curr_z < min_z) {
        found_hit = true;
        hit_name.assign(name.begin(), name.end());
        min_z = curr_z;
      }
    }
    
    // Return to the original state
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();  // Restore previous projection matrix
    glMatrixMode(GL_MODELVIEW);
    
    if (found_hit)
      return hit_name[0];
    else
      return -1;
}

/*
 * DRAW(mode)
 * 
 *   Input:
 *      mode - the desired rendering mode (eg. flat, smooth)
 *
 *   Output: 
 *      none
 */
void Model::draw(GLuint mode)
{
  // Selection mode: draw each face with a unique name
  if (mode&OBJ_SELECT) {
  
    // Draw the scene without lighting or anything 
    glDisable(GL_LIGHTING);
    glDisable(GL_COLOR_MATERIAL);
    
    int i, j, jmax;
    Vector3 vert;
    
    // Give each face a unique name (its index)
    for (i=0; i < curr_faces->size(); i++) {
      jmax = (*curr_faces)[i].v_indices.size();    
      
      // Give each face a unique name - it's index
      glLoadName(i);
      glBegin(GL_TRIANGLE_FAN);
      for (j=0; j < jmax; j++) {
        vert = (*curr_vertices)[(*curr_faces)[i].v_indices[j]].v;
        glVertex3f(vert[0], vert[1], vert[2]);
      }
      glEnd();
    }
    glFlush();
  
  }
}
