I have the following code:
#define GLUT_DISABLE_ATEXIT_HACK
#include <GL/glut.h>
#include <GL/gl.h>
#include <math.h>
#include <stdio.h>
GLfloat ctrlptsBezier[4][4][3] =
{
{
{-2.0, -2.0, 1.0},
{-0.5, -2.0, 0.0},
{0.5, -2.0, 0.0},
{2.0, -2.0, 1.0}},
{
{-2, -0.5, -1.0},
{-0.5, -0.5, 0.0},
{0.5, -0.5, 0.0},
{2.0, -0.5, 0.0}},
{
{-2, 0.5, 0.0},
{-0.5, 0.5, -2.0},
{0.5, 0.5, 0.0},
{2.0, 0.5, 0.0}},
{
{-2.0, 2.0, 1.0},
{-0.5, 2.0, 0.0},
{0.5, 2.0, 0.0},
{2.0, 2.0, 1.0}}
};
int uSteps = 30;
int vSteps = 30;
bool shade = false;
GLfloat black [] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat blue[] = { 0.0, 0.0, 1.0, 1.0 };
GLfloat green[] = { 0.0, 1.0, 0.0, 1.0 };
GLfloat peach[] = { 1.0, 0.5, 0.5, 1.0 };
GLfloat purple[] = { 0.5, 0.0, 0.5, 1.0 };
GLfloat red[] = { 1.0, 0.0, 0.0, 1.0 };
GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat yellow[] = { 1.0, 1.0, 0.0, 1.0 };
//Initial eye/viewpoint coords.
double xPos = -20.0, zPos = -20.0;
double eyeHeight = 4.5;
double eyeIncline = -0.5;
double theta = 0.0; //Rotation angle in rads
//Movement params (camera)
double posIncr = 0.25;
double thetaIncr = 0.1;
#define BUFSIZE 512 //Pick buffer size
void setObjLight( bool s )
{
int shadeNumber = GL_FLAT;
if ( shade == true )
shadeNumber = GL_SMOOTH;
glShadeModel(shadeNumber);
}
void setLights(void)
{
setObjLight(shade);
}
void drawRoom(void)
{
GLfloat floor_color[] = { 0.5, 0.5, 0.5, 1.0 }; //Grey floor
GLfloat blue_wall[] = { 0.0, 0.0, 1.0, 1.0 };
GLfloat green_wall[] = { 0.0, 1.0, 0.0, 1.0 };
GLfloat purple_wall[] = { 0.5, 0.0, 0.5, 1.0 };
//FLOOR
glMaterialfv(GL_FRONT, GL_DIFFUSE, floor_color);
glBegin(GL_POLYGON);
glNormal3f(0.0, 1.0, 0.0);
glVertex3f(-25.0, 0.0, -25.0);
glVertex3f( 25.0, 0.0, -25.0);
glVertex3f( 25.0, 0.0, 25.0);
glVertex3f(-25.0, 0.0, 25.0);
glEnd();
//WALLS
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, blue_wall);
glPushMatrix();
glTranslatef(0.0, 0.0, 25.0);
glBegin(GL_POLYGON);
glNormal3f(0.0, 1.0, 0.0);
glVertex3f(-25.0,-25.0,0.0);
glVertex3f(25,-25.0,0);
glVertex3f(25, 25, 0);
glVertex3f(-25, 25, 0);
glEnd();
glPopMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, green_wall);
glPushMatrix();
glTranslatef(0.0, 0.0, -25.0);
glBegin(GL_POLYGON);
glNormal3f(0.0, 1.0, 0.0);
glVertex3f(-25.0,-25.0,0.0);
glVertex3f(25,-25.0,0);
glVertex3f(25, 25, 0);
glVertex3f(-25, 25, 0);
glEnd();
glPopMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, purple_wall);
glPushMatrix();
glTranslatef(25.0, 0.0, 0.0);
glRotatef(90.0, 0.0, 1.0, 0.0);
glBegin(GL_POLYGON);
glNormal3f(0.0, 1.0, 0.0);
glVertex3f(-25.0,-25.0,0.0);
glVertex3f(25,-25.0,0);
glVertex3f(25, 25, 0);
glVertex3f(-25, 25, 0);
glEnd();
glPopMatrix();
}
void drawShapes()
{
//SPHERE
glPushMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, blue);
glNormal3f(0.0, 1.0, 0.0);
glTranslatef(0.0, 2.0, 0.0);
glLoadName(1);
glutSolidSphere (2.0, 20, 16);
glPopMatrix();
glFlush();
//CONE
glPushMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, purple);
glNormal3f(0.0, 1.0, 0.0);
glTranslatef(5.0, 0.0, 0.0);
glRotatef(-90.0, 1.0, 0.0, 0.0);
glLoadName(2);
glutSolidCone (2.0, 3, 20, 16);
glPopMatrix();
glFlush();
glLoadName(0);
}
void drawBezier()
{
glEnable(GL_MAP2_VERTEX_3);
glPushMatrix();
glTranslatef(10, 2, 15);
glMaterialfv(GL_FRONT, GL_DIFFUSE, white);
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlptsBezier[0][0][0]);
glMapGrid2f(uSteps, 0.0, 1.0, vSteps, 0.0, 1.0);
glEvalMesh2(GL_FILL, 0, uSteps, 0, vSteps);
glPopMatrix();
glPushMatrix();
glTranslatef(13, 2, 18);
glRotatef(-90, 0.0, 1.0, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, red);
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlptsBezier[0][0][0]);
glMapGrid2f(uSteps, 0.0, 1.0, vSteps, 0.0, 1.0);
glEvalMesh2(GL_FILL, 0, uSteps, 0, vSteps);
glPopMatrix();
glPushMatrix();
glTranslatef(7, 2, 18);
glRotatef(90, 0.0, 1.0, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, yellow);
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlptsBezier[0][0][0]);
glMapGrid2f(uSteps, 0.0, 1.0, vSteps, 0.0, 1.0);
glEvalMesh2(GL_FILL, 0, uSteps, 0, vSteps);
glPopMatrix();
glPushMatrix();
glTranslatef(10, 2, 21);
glRotatef(180, 0.0, 1.0, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, peach);
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlptsBezier[0][0][0]);
glMapGrid2f(uSteps, 0.0, 1.0, vSteps, 0.0, 1.0);
glEvalMesh2(GL_FILL, 0, uSteps, 0, vSteps);
glPopMatrix();
glPushMatrix();
glTranslatef(10, 5, 18);
glRotatef(90.0, 1.0, 0.0, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, black);
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlptsBezier[0][0][0]);
glMapGrid2f(uSteps, 0.0, 1.0, vSteps, 0.0, 1.0);
glEvalMesh2(GL_FILL, 0, uSteps, 0, vSteps);
glPopMatrix();
//Sphere for filler
glPushMatrix();
glTranslatef(10, 2, 18);
glRotatef(90.0, 1.0, 0.0, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, white);
glutSolidSphere(3.0, 20, 16);
glPopMatrix();
glFlush();
}
void drawScene(void)
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
double atx = xPos + cos(theta);
double atz = zPos + sin(theta);
double atHeight = eyeHeight + eyeIncline;
gluLookAt(xPos, eyeHeight, zPos, atx, atHeight, atz, 0.0, 1.0, 0.0);
glPushMatrix();
setLights();
drawRoom();
drawShapes();
glLoadName(3);
drawBezier();
glPopMatrix();
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawScene();
glutSwapBuffers();
}
void setProjection(void)
{
gluPerspective(60.0, 1.0, 0.1, 100.0);
}
void init(void)
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_LIGHTING);
glEnable(GL_FLAT); //Flat shading initially
glShadeModel(GL_FLAT);
//LIGHTING
GLfloat specular[]= {1.0, 1.0, 1.0, 1.0};
GLfloat diffuse[]= {1.0, 1.0, 1.0, 1.0};
GLfloat ambient[]= {1.0, 1.0, 1.0, 1.0};
GLfloat shininess= {100.0};
GLfloat light_ambient[]= {0.0, 0.0, 0.0, 1.0};
GLfloat light_diffuse[]= {1.0, 1.0, 1.0, 1.0};
GLfloat light_specular[]= {1.0, 1.0, 1.0, 1.0};
GLfloat light_position[]= {10.0, 10.0, 10.0, 0.0};
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
// /LIGHTING
glEnable(GL_NORMALIZE);
glClearColor (0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
}
void specialKey(int k, int x, int y) //Camera movement commands with arrow keys
{
switch (k) {
case GLUT_KEY_UP:
xPos += posIncr * cos(theta);
zPos += posIncr * sin(theta);
break;
case GLUT_KEY_DOWN:
xPos -= posIncr * cos(theta);
zPos -= posIncr * sin(theta);
break;
case GLUT_KEY_LEFT:
theta -= thetaIncr;
break;
case GLUT_KEY_RIGHT:
theta += thetaIncr;
break;
case GLUT_KEY_PAGE_UP:
eyeIncline += 0.5;
break;
case GLUT_KEY_PAGE_DOWN:
eyeIncline -= 0.5;
break;
case GLUT_KEY_HOME:
eyeHeight += 0.5;
break;
case GLUT_KEY_END:
eyeHeight -= 0.5;
break;
default:
return;
}
glutPostRedisplay();
}
void key(unsigned char k, int x, int y)
{
if ( k == 27 ) //ESC to close
exit(0);
glutPostRedisplay();
}
void processHits(GLint hits, GLuint buffer[])
{
unsigned int j;
GLuint names, *ptr;
float z1, z2;
printf ("hits = %d\n", hits);
ptr = (GLuint *) buffer;
shade = !shade;
setLights();
glutPostRedisplay();
for (int i = 0; i < hits; i++)
{ /* for each hit */
names = *ptr;
printf (" number of names for hit = %d\n", names); ptr++;
z1 = (float) *ptr/0x7fffffff; ptr++;
z2 = (float) *ptr/0x7fffffff; ptr++;
printf(" z1 is %g;",z1);
printf(" z2 is %g\n", z2);
printf (" the name is ");
for (j = 0; j < names; j++) { /* for each name */
printf ("%d ", *ptr); ptr++;
}
printf ("\n");
}
}
void pick( int button, int state, int x, int y )
{
GLuint selectBuf[BUFSIZE];
GLint hits;
GLint viewport[4];
if (button != GLUT_LEFT_BUTTON || state != GLUT_DOWN) {
return;
}
glSelectBuffer(BUFSIZE, selectBuf);
glRenderMode(GL_SELECT);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glGetIntegerv(GL_VIEWPORT, viewport);
gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y), 5.0, 5.0, viewport); //5x5 pixel area around the mouse for selecting
gluPerspective(75, 1.0, 0.1, 100); //NEED
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glInitNames();
glPushName(0);
drawScene();
glPopMatrix();
glFlush();
hits = glRenderMode(GL_RENDER); //# of hits assigned
processHits(hits, selectBuf);
}
void reshape(int w, int h){
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(75, w/h,1,150);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutCreateWindow("Room");
init();
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutSpecialFunc(specialKey);
glutReshapeFunc(reshape);
glutMouseFunc(pick);
glutMainLoop();
return 0;
}
Forgive me for the length. I am trying to get picking to work so that I can select one object at a time to do things with. According to my print outs, it is functioning as I expect, except for one hurdle: When you pick an object, you end up extremely zoomed in, basically inside the selected shape. I have combed my code, and made some changes/debugging efforts, but I can't find the problem line. Can anyone point me in the right direction as to why picking gives this strange behavior?
Your function
pick
change the projection matrix withgluperspective
(to zoom on the picking area), but it fails to restore the previous matrix state: it can be easily fixed by wrapping the the drawing part of the function with a set ofglPushMatrix
andglPopMatrix
while in matrixGL_PROJECTION
mode.