Problems with (selection mode) picking

I’ve spent a couple of days, and multiple books, trying to implement picking for multiple 2D shapes. Currently however I only have one shape, and I’ve been trying to make it so that you can click and drag the shape around the canvas.

My problem is that, after multiple attempts, I always arrive at a situation where clicking and dragging anywhere moves the shape, rather than only if you click within the area of the shape.

Could someone please take a quick look at my code to see if theres an obvious mistake I’m making. I would be very thankful.

The main/canvas class:

#include <cstdlib>
#include <gl/glut.h>
#include "TableComponent.h"
#define SIZE 512

using namespace std;

int w = 250, h = 250;
float ratio = 1.0;
unsigned char buttons[2] = {0};
float mouseX, mouseY = 0;
TableComponent *t = new TableComponent(556, 100,100, 50, 50);
bool check = false;
GLuint selectBuf[SIZE];
GLint hits;
int mode = GL_RENDER;

void glEnable2D()
{
	int vPort[4];
	
	glGetIntegerv(GL_VIEWPORT, vPort);
	
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();	
	glOrtho(0, vPort[2], 0, vPort[3], -1, 1);

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
}

void glDisable2D()
{
   glMatrixMode(GL_PROJECTION);
   glPopMatrix();   
   glMatrixMode(GL_MODELVIEW);
   glPopMatrix();	
}

void init()
{
	glClearColor(0.0, 0.0, 0.0, 1.0);
	glDisable(GL_DEPTH_TEST);
	glShadeModel(GL_FLAT);
}

void reshape(int width, int height)
{
	w = width;
	h = height;
	int vPort[4];	
	glGetIntegerv(GL_VIEWPORT, vPort);
	glViewport(0, 0, (GLsizei) width, (GLsizei) height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, vPort[2], 0, vPort[3], -1, 1);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void startPicking() 
{
	GLint viewport[4];
	glSelectBuffer(SIZE,selectBuf);
	glGetIntegerv(GL_VIEWPORT,viewport);
	glRenderMode(GL_SELECT);	
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluPickMatrix(mouseX,viewport[3]-mouseY,1,1,viewport);
	glOrtho(0, viewport[2], 0, viewport[3], -1, 1);
	glMatrixMode(GL_MODELVIEW);
	glInitNames();
	glPushName(0);
}

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

	ptr = (GLuint *) buffer;

	for (i= 0; i < hits; i++)
	{
		names = *ptr;
		ptr += 3;
		for (j = 0; j < names; j++)
		{
			if (*ptr == t->getName())
			{
				check = true;
			}
			else
			{
				check = false;
			}
			ptr++;
		}
	}
}

void stopPicking() 
{
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glFlush();
	hits = glRenderMode(GL_RENDER);
	if (hits != 0){
		processHits(hits,selectBuf);
	}
	mode = GL_RENDER;
}

void display()
{
	//display crap
	glClear(GL_COLOR_BUFFER_BIT);
	if (mode == GL_SELECT) 
	{
		startPicking();
	}
	glEnable2D();      
	  t->draw(mode);
	glDisable2D();
	if (mode == GL_SELECT)
	{
		stopPicking();
	}
	else
	{
		glutSwapBuffers();
		glFlush();
	}	
}

void mouseResponse(int button, int state, int xPos, int yPos)
{
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{
		mouseX = xPos;
		mouseY = yPos;
		buttons[0] = 1;
		mode = GL_SELECT;
	}
	else if (state == GLUT_UP)
	{
		buttons[0] = 0;
	}
	glutPostRedisplay();
}

void mouseMotion(int x, int y)
{
	if( buttons[0] && check == true )
	{
		float xDiff = (x - mouseX); // how far the mouse has moved horizontally
		float yDiff = (mouseY - y); // how far the mouse has moved vertically
		mouseX = x;
		mouseY = y;
		int testx = t->getX();
		int testy = t->getY();
		t->setX((testx + (float) xDiff));
		t->setY((testy + (float) yDiff));
	}
	glutPostRedisplay();
}

int main(int argc, char **argv)
{
   glutInit(&argc, argv);

   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
   glutInitWindowPosition(100,100); // set the window's position
   glutInitWindowSize(w,h); // set the size of the window
   glutCreateWindow("Tabletop Interface");
   init();
   //glutFullScreen(); // set the display to fullscreen

   glutDisplayFunc(display); // our display function
   glutReshapeFunc(reshape); // called when we resize the window
   //glutKeyboardFunc(keyboard); // called when a key is pressed   
   glutMouseFunc(mouseResponse);
   glutMotionFunc(mouseMotion);

   // start the main loop
   glutMainLoop();
   return(0);
}

  

The object/square class:

#include "TableComponent.h"

TableComponent::TableComponent(int id, int w, int h, int xPos, int yPos)
{
	name = id;
	width = w;
	height = h;
	x = xPos;
	y = yPos;
}

TableComponent::TableComponent()
{
}

void TableComponent::draw(GLenum mode)
{
	if (mode == GL_SELECT) glLoadName(name);
	glTranslatef(x,y,0);
	glBegin(GL_QUADS);
	  glColor3f(1.0, 1.0, 1.0);
      glVertex2d(0, 0);
	  glVertex2d(0, height);
	  glVertex2d(width, height);
	  glVertex2d(width, 0);
    glEnd();	
}

void TableComponent::setX(int xPos)
{
	x = xPos;
}

void TableComponent::setY(int yPos)
{
	y = yPos;
}

int TableComponent::getX()
{
	return x;
}

int TableComponent::getY()
{
	return y;
}

int TableComponent::getName()
{
	return name;
}  

Anyone :frowning:

Hi

Try rendering your scene in false colors to the backbuffer, the color beeing the ID of the object. Then a simple glReadPixels at the mouse position (don’t forget to reverse y axis) will tell you which object has been picked.

Here’s a hint for you. What is the projection matrix when drawing the object? Does gluPickMatrix have any effect on the final matrix? If mode is GL_SELECT, startPicking is called, followed by a call to glEnable2D.

It’s a desing problem in my oppinion. You’re doing the same thing in different parts of the code. One and only one function should be responsible for the projection matrix. That function should take into concideration if you want the pick matrix or not.

Right now you have THREE functions setting the projection matrix, and they don’t cooperate very well. Or rather, they don’t cooperate at all.