6

I have been searching all day for a tutorial or example code for a simple program - click on object (like a 2D rectangle for example) then as you hold and move the mouse the object follows the mouse, then on mouse release the object remains in new location. In other words, I want to understand how to drag and drop an object with the mouse events.

Could anyone help to point me in the right direction of any useful sources of information relating to this problem?

Yun
  • 3,056
  • 6
  • 9
  • 28
sebjwallace
  • 753
  • 1
  • 8
  • 17

4 Answers4

9

Thanks for all the responses so far.

I have worked out how to do it, so I will go ahead an answer my own question.

I am using GLUT as a mouse handler:

  1. When the mouse is clicked and moving (glutMotionFunc) the drag function is called.

  2. In the drag function the mouse coordinates (x,y) are converted to a Points struct while being converted into window coordinates.

  3. If the mouse is within the square then drag the square by changing it's coordinates and redisplay.

I am still very new to OpenGL and C++ so I do apologize for the messy coding. I am a bit frustrated in doing it this way as the redrawn square makes it seem the cursor snaps to the center. I welcome alternative solutions to this problem and criticism of my code, for learning purposes.

CODE (included glut and using namespace std):

// points structure made of two coordinates; x and y
struct Points
{
    float x,y;  // initializor
    Points() { x = 0.0; y = 0.0; } // constructor

    Points(float _x, float _y) : x(_x), y(_y) {}
};

// square made of 4 points
class Square
{
public:
    Points pts[4]; // square structure
    Square(); // initialize constructor

    void draw(Square *sqr); // draw square
    Points mouse(int x, int y); // get mouse coordintaes
    Square* drag(Square *sqr, Points *mouse); // change points of sqr
};

// square constructor
Square::Square()
{
    pts[0] = Points(0.2,0.2);
    pts[1] = Points(0.4,0.2);
    pts[2] = Points(0.4,0.4);
    pts[3] = Points(0.2,0.4);
};

// draw function
void Square::draw(Square *sqr)
{
    // draw square fill
    int i;
    glColor3f(0.2, 0.2, 0.2);
    glBegin(GL_QUADS);
    for (i = 0; i < 4; ++i)
    {
        glVertex2f(sqr->pts[i].x, sqr->pts[i].y);
    }
    glEnd();
    // draw square points
    i = 0;

    glColor3f(1.0, 1.0, 1.0);
    glBegin(GL_POINTS);
    for (i = 0; i < 4; ++i)
    {
        glVertex2f(sqr->pts[i].x, sqr->pts[i].y);
    }
    glEnd();
}

// mouse function
Points Square::mouse(int x, int y)
{
    int windowWidth = 400, windowHeight = 400;
    return Points(float(x)/windowWidth, 1.0 - float(y)/windowHeight);
}

// drag function
Square* Square::drag(Square *sqr, Points *mouse)
{
    sqr->pts[0].x = mouse->x - 0.1;
    sqr->pts[0].y = mouse->y - 0.1;
    sqr->pts[1].x = mouse->x + 0.1;
    sqr->pts[1].y = mouse->y - 0.1;

    sqr->pts[3].x = mouse->x - 0.1;
    sqr->pts[3].y = mouse->y + 0.1;

    sqr->pts[2].x = mouse->x + 0.1;
    sqr->pts[2].y = mouse->y + 0.1;

    return sqr;
}

// GLOBAL

// create square object
Square* sqr = new Square;


// display at start
void display() {
    glClear(GL_COLOR_BUFFER_BIT);
    sqr->draw(sqr);
    glFlush();
}

// drag function
void drag (int x, int y)
{
    // int x and y of mouse converts to screen coordinates
    // returns the point as mousePt
    Points mousePt = sqr->mouse(x,y);
    //create pointer to window point coordinates
    Points* mouse = &mousePt;

    // if the mouse is within the square
    if (mouse->x > sqr->pts[0].x && mouse->y > sqr->pts[0].y)
    {       
        if (mouse->x < sqr->pts[2].x && mouse->y < sqr->pts[2].y)
        {
            // then drag by chaning square coordinates relative to mouse
            sqr->drag(sqr,mouse);
            glutPostRedisplay();
        }
    }
}


void Initialize() {
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}

int main(int iArgc, char** cppArgv) {

    glutInit(&iArgc, cppArgv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(400, 400);
    glutInitWindowPosition(200, 200);
    glutCreateWindow("Move Box");


    glutMotionFunc(drag);

    Initialize();
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}
Community
  • 1
  • 1
sebjwallace
  • 753
  • 1
  • 8
  • 17
5

OpenGL is only concerned with the drawing process. Everything else (mouse input, object picking, scene management/alterations, etc.) is completely up to you to implement.

Here's a rough outline:

  1. Install a mouse click event handler (the exact method to use depends on the framework used and/or the operating system)

  2. In the mouse click event handler perform a picking operation. This usually involves unprojecting the mouse window position into the world space (see gluUnproject) resulting in a ray. Test each object in the scene if it intersects with the ray; you'll have to implement this yourself, because OpenGL just draws thing (there is no such thing as a "scene" in OpenGL).

  3. If a object has been picked register it to be manipulated in the mouse drag handler

  4. everytime a mouse drag event happens adjust the object's position data and trigger of the OpenGL display (you always redraw the whole thing in OpenGL).

  5. When the mouse is released unregister the object from the drag handler.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • Thanks for your guidelines. I think I will be using GLUT for event handling. It seems it is a bit more complex of a problem than I thought. – sebjwallace Nov 29 '13 at 15:40
0

As mentioned by others, OpenGL does not handle user input. You want to use a library for that. If you want a more all-around solution, you can even use a more complete render or physics engine.

For simple user input, you can use SDL (e.g. this is for mouse input).

For more complete 2D stuff, you can just use Box2D. Here are a whole bunch of tutorials.

The heavy-weight solution is a complete render engine, such as Ogre3D or CrystalSpace.

Domi
  • 22,151
  • 15
  • 92
  • 122
0

As mentioned by others, you need to get a mouse handler to get the mouse position first. Then you need a way to pick an object. You have a few options to do the picking in OpenGL.

  1. If you are using classic OpenGL, you can use the select buffer. The following link is a good tutorial http://www.lighthouse3d.com/opengl/picking/index.php3?openglway
  2. If you are using modern opengl, which is shader based, you can use FBO based picking. http://ogldev.atspace.co.uk/www/tutorial29/tutorial29.html
  3. You can always implement a ray tracking picking yourself in both cases. The gluUnproject can help a lot in the implementation. http://schabby.de/picking-opengl-ray-tracing/

After that, you just need to update the object position according to the mouse movement or acceleration.

sirian_ye
  • 610
  • 6
  • 11