PDA

View Full Version : Problems with (selection mode) picking



Phoresis
02-05-2007, 03:27 AM
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 &amp;&amp; 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] &amp;&amp; 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(&amp;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;
}

Phoresis
02-05-2007, 07:01 AM
Anyone :(

sharp_pixel
02-06-2007, 01:04 AM
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.

Bob
02-06-2007, 01:06 AM
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.