Selection Program Questions

Hi,

I’m working on an application that enables the user to drag a sphere with the mouse. The application has two subwindows, one containing a front view and the other a top view (these divide the main window in half horizontally). The viewing position cannot be changed by the user. The app also includes three cubes that can be selected but which cannot be moved. I’m using OpenGLUT.

I’ve run into several problems:

  1. I initially developed the application with only a single window. In this case, the QUAD representing the ground appeared as expected. However, when I split the display into two subwindows the ground QUAD disappeared. The drawing code is definitely being reached however the QUAD is not appearing. Any idea why this is happeing?

  2. When the user selects an object with the mouse, all of the objects in the subwindow disappear. However, as soon as the window is resized they appear correctly. Something is obviously going wrong in either the pickObjects or the proces****s functions. The basic approach I’m using here is to detect a hit, and then set a variable in a global array that represents a hit on the object. This array is tested in the display function so that an object that has registered a hit is drawn in red. I’m not sure why the objects in the subwindow are disappearing.

Here’s the code I’m using (which is a combination of the Lighthouse Subwindows tutorial and the Redbook pickdepth example):

#include <GL/openglut.h>
#include <stdlib.h>
#include <stdio.h>

#define BUFSIZE			512
#define ESC				27
#define WINDOW_WIDTH	900
#define WINDOW_HEIGHT	700
#define BORDER			5

float	gObjx = 0.0;								// X coordinate of dragged object.
float	gObjy = 3.0;								// Y coordinate of dragged object.
float	gObjz;										// Z coordinate of dragged object.
float	gRedColour[3] = {0.75, 0.0, 0.0};
float	gGreenColour[3] = {0.0, 0.75, 0.0};
float	gBlueColour[3] = {0.0, 0.0, 0.75};
float	gOrangeColour[3] = {0.75f, 0.6f, 0.0f};
double	gRatio;
int		gHitArray[BUFSIZE] = {0};					// Hit array.
int		gMainWindow, gSubWindow1, gSubWindow2;
int		h = WINDOW_WIDTH, w = WINDOW_HEIGHT;

//*********************************************************************\\

void init(void)
{
	glClearColor(0.5f, 0.5f, 0.5f, 0.0f);			// Grey clear colour.
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);
	glShadeModel(GL_FLAT);
	
	gRatio = (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT;
}

//*********************************************************************\\

void drawScene(GLenum mode)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	if(mode != GL_SELECT)						// These objects are not selectable.
	{
		glColor3fv(gBlueColour);				// Ground.
		glBegin(GL_QUADS);
			glVertex3i(-5, 0, -5);
			glVertex3i(5, 0, -5);
			glVertex3i(5, 0, 5);
			glVertex3i(-5, 0, 5);
		glEnd();
	}

	if(mode == GL_SELECT)						// Object 1.		
		glLoadName(1);
	if(gHitArray[0] == TRUE)
		glColor3fv(gRedColour);
	else
		glColor3fv(gGreenColour);
	
	glPushMatrix();
	glTranslatef(-3.0, 1.0, 0.0);
	glutSolidCube(2.0);
	glPopMatrix();

	if(mode == GL_SELECT)						// Object 2.
		glLoadName(2);
	if(gHitArray[1] == TRUE)
		glColor3fv(gRedColour);
	else
		glColor3fv(gGreenColour);
	glPushMatrix();
	glTranslatef(0.0, 1.0, 0.0);
	glutSolidCube(2.0);
	glPopMatrix();

	if(mode == GL_SELECT)						// Object 3.		
		glLoadName(3);
	if(gHitArray[2] == TRUE)
		glColor3fv(gRedColour);
	else
		glColor3fv(gGreenColour);
	glPushMatrix();
	glTranslatef(3.0, 1.0, 0.0);
	glutSolidCube(2.0);
	glPopMatrix();	
	
	if(mode == GL_SELECT)						// Object 4.		
		glLoadName(4);
	if(gHitArray[3] == TRUE)
		glColor3fv(gRedColour);
	else
		glColor3fv(gOrangeColour);	
	glPushMatrix();								// Sphere for drag testing.
	glTranslatef(gObjx, gObjy, 0.0f);
	glutSolidSphere(0.5, 32, 32);
	glPopMatrix();

	glutSwapBuffers();
}

//*********************************************************************\\

void processHits(GLint hits, GLuint buffer[])
{
	int i;
	unsigned j;
	GLuint names, *ptr;
	   
	printf("hits = %d

", hits);
	ptr = (GLuint *) buffer;
	   
	for(i = 0; i < hits; i++)				// For each hit.
	{  
		names = *ptr;
		printf("Number of objects selected: %d
", names); 
		ptr++;
		//printf("z1 is %g
", (float) *ptr/0x7fffffff); 
		ptr++;
		//printf("z2 is %g
", (float) *ptr/0x7fffffff); 
		ptr++;
		printf("The selected object is: ");
		for (j = 0; j < names; j++)			// For each name.
		{  
			printf("%d ", *ptr);				
			gHitArray[*ptr - 1] = TRUE;		// Set the hit array here.
			ptr++;
		}
		printf("

");
	}
}

//*********************************************************************\\

void pickObjects(int button, int state, int x, int y)
{
	GLuint selectBuf[BUFSIZE];
	GLint hits = 0;
	GLint viewport[4];
	int i;

	if(button != GLUT_LEFT_BUTTON &#0124;&#0124; state != GLUT_DOWN)
	{
			for(i = 0; i < BUFSIZE; i++)
				gHitArray[i] = FALSE;
			glutPostRedisplay();
			return;
	}

	glGetIntegerv(GL_VIEWPORT, viewport);

	glSelectBuffer(BUFSIZE, selectBuf);
	   
	glRenderMode(GL_SELECT);

	glInitNames();
	glPushName(0);

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
		
	gluPickMatrix((GLdouble) x, (GLdouble) ((viewport[3]) - y), 5.0, 5.0, viewport);		 //  Create 5x5 pixel picking region near cursor location.
	gluPerspective(45, gRatio, 1.0, 1000);

	drawScene(GL_SELECT);
	glPopMatrix();
	glFlush();

	hits = glRenderMode(GL_RENDER);
	   
	if(hits)
	{
		processHits(hits, selectBuf);
		glutPostRedisplay();
	}
}

//*********************************************************************\\

void moveMouse(int x, int y)
{
	if(gHitArray[3] == TRUE)
	{
		GLint viewport[4];
		GLdouble mvmatrix[16], projmatrix[16];
		GLint realy;														//  OpenGL y coordinate position.
		GLdouble wx, wy, wz;												//  returned world x, y, z coords.

		glGetIntegerv(GL_VIEWPORT, viewport);
		glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
		glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
																		
		realy = viewport[3] - (GLint)y - 1;									// viewport[3] is height of window in pixels.
		printf("Coordinates at cursor are (%4d, %4d)
", x, realy);
		gluUnProject((GLdouble) x, (GLdouble) realy, 0.935, mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
		printf("World coords at z = 0.5: (%f, %f, %f)

", wx, wy, wz);
		gObjx = (GLfloat)wx;
		gObjy = (GLfloat)wy;
		glutPostRedisplay();
	}
}

//*********************************************************************\\

void renderScene(void)
{
	glutSetWindow(gMainWindow);
	glClear(GL_COLOR_BUFFER_BIT);
	glutSwapBuffers();
}

//*********************************************************************\\

void renderScenesw1(void)							// Front view.
{
	glutSetWindow(gSubWindow1);
	glLoadIdentity();
	gluLookAt(0.0, 1.0, 20.0,						
		      0.0, 0.0, -1.0,
			  0.0, 1.0, 0.0);
	drawScene(GL_RENDER);
}

//*********************************************************************\\

void renderScenesw2(void)							// Top view.
{
	glutSetWindow(gSubWindow2);
	glLoadIdentity();
	gluLookAt(0.0, 20.0, 0.0,						
		      0.0, -1.0, 0.0,
			  0.0, 0.0, -1.0);
	drawScene(GL_RENDER);
}

//*********************************************************************\\

void renderSceneAll(void) 
{
	renderScenesw1();
	renderScenesw2();
}

//*********************************************************************\\

void changeSize2(int w1, int h1)
{
	gRatio = 1.0f * w1 / h1;
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	
	glViewport(0, 0, w1, h1);

	gluPerspective(45, gRatio, 1.0, 1000);
	glMatrixMode(GL_MODELVIEW);
}

//*********************************************************************\\

void changeSize1(int w1, int h1)
{
	if(h1 == 0)
		h1 = 1;

	w = w1;
	h = h1;

	glutSetWindow(gSubWindow1);
	glutPositionWindow(0, 0);
	glutReshapeWindow(w / 2, h);
	changeSize2(w / 2, h);
	
	glutSetWindow(gSubWindow2);
	glutPositionWindow(0 + (w / 2), 0);
	glutReshapeWindow(w / 2, h);
	changeSize2(w / 2, h);
}

//*********************************************************************\\

void keyboard(unsigned char key, int x, int y)
{
   switch(key)
   {
      case ESC:
         exit(0);
         break;
   }
}

//*********************************************************************\\

int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
	glutInitWindowPosition(100, 100);
	gMainWindow = glutCreateWindow("Test");
		init();
		glutReshapeFunc(changeSize1);
		glutDisplayFunc(renderScene);
		glutIdleFunc(renderSceneAll);
		glutMouseFunc(pickObjects);
		//glutMotionFunc(moveMouse);
		glutKeyboardFunc(keyboard);
	gSubWindow1 = glutCreateSubWindow(gMainWindow, 0, 0, WINDOW_WIDTH / 2, WINDOW_HEIGHT);
		init();
		glutDisplayFunc(renderScenesw1);
		glutMouseFunc(pickObjects);
		//glutMotionFunc(moveMouse);
		glutKeyboardFunc(keyboard);
	gSubWindow2 = glutCreateSubWindow(gMainWindow, WINDOW_WIDTH / 20, 0, WINDOW_WIDTH / 2, WINDOW_HEIGHT);
		init();
		glutDisplayFunc(renderScenesw2);
		glutMouseFunc(pickObjects);
		//glutMotionFunc(moveMouse);
		glutKeyboardFunc(keyboard);
	glutMainLoop();
	return 0; 
}
 

Any help with this would be much appreciated.

Cheers,

Chris

That’s a lot of code to sort through. Lighthouse has a complete picking example. Have you looked at that? It might help to start with a working example and then build from there.

Hi,

Thanks for the reply.

I did say that the code is partly based on the Lighthouse example. I think I understand that example. The problems are happening when I extend the example by adding the extra subwindow.

I think the problem lies somewhere in the pickObjects, proces****s and drawScene functions although I’m not sure where.

Cheers,

Chris

OT: darn 4 letter word filter :slight_smile: impossible to spell “process Hits” in a single word