Using GLFW to capture mouse dragging? [C++]
Asked Answered
C

2

5

So i'm trying to capture mouse dragging in my OpenGL application. I've done the following so far:

glfwSetMouseButtonCallback(window, mouse_callback);

static void mouse_callback(GLFWwindow* window, int button, int action, int mods)
{
    if (button == GLFW_MOUSE_BUTTON_LEFT) {
        double x;
        double y;
        glfwGetCursorPos(window, &x, &y);

        if (previous_y_position - y > 0)
        {
            camera_translation.y -= 1.0f;
            previous_y_position = y;
        }
        else
        {
            camera_translation.y += 1.0f;
            previous_y_position = y;
        }
    }
}

The problem with this though is if I would like to zoom in I need to move my mouse upwards and then click repeatedly. For some reason if I press down on the left mouse button and drag upwards it does nothing.

Coenobite answered 12/5, 2016 at 18:31 Comment(1)
Did you step through the code with a debugger? The code you posted doesn't look like much so as long as it's getting called and the variables are getting updated the problem is in code you did not include. This is why it's imported for you to provide a Minimal, Completed. Verifiable Example.Pinball
R
6

In cursor_pos_callback, just confirm if the button is pressed, and that works.

void mouse_cursor_callback( GLFWwindow * window, double xpos, double ypos)  
{

  if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE) 
  {
     return;
  }

  // `write your drag code here`
}
Recitation answered 25/5, 2018 at 4:7 Comment(1)
This is the easiest way to simulate drag I found. Should be ==GLFW_PRESSWarpath
S
5

mouse_callback is stateless. It receives events, momentary "actions". You need to make your program to "remember" that mouse button is pressed. So that when button is pressed in a frame 1, you can refer to this information in all the frames after that and before mouse button is released.

The simple way is to flip a boolean flag on press/release:

static void mouse_callback(GLFWwindow* window, int button, int action, int mods)
{
    if (button == GLFW_MOUSE_BUTTON_LEFT) {
        if(GLFW_PRESS == action)
            lbutton_down = true;
        else if(GLFW_RELEASE == action)
            lbutton_down = false;
    }

    if(lbutton_down) {
         // do your drag here
    }
}

Schematically:

state                  released               pressed                released
timeline             -------------|------------------------------|---------------
                                  ^                              ^
mouse_callback calls          GLFW_PRESS                    GLFW_RELEASE

The hard way is to use a state machine (especially if you need more complicated combinations of states of input controllers).

Spriggs answered 12/5, 2016 at 18:49 Comment(9)
Nope that didn't work. It seems like glfwGetCursorPos doesn't update until the mouse_button is released.Coenobite
Where do you call it?Spriggs
I call glfwSetMouseButtonCallback(window, mouse_callback); once before my game loop while (!glfwWindowShouldClose(window))Coenobite
I mean glfwGetCursorPos Spriggs
I only ever call it inside of the boolean like in your codeCoenobite
This is a common pattern in game development. It always works. You screwed it somewhere. Run your debugger then to see how exactly state transitions and coordinate update.Spriggs
So I moved the boolean check out from the mouse_callback and into my game loop. Everything works now.Coenobite
Right. It should not be in the callback. I even shown myself on the schema that callback is being called only twice ;)Spriggs
@Drop, but this approach will indicate that the mouse is being dragged even for a single click due to the fact that while-loop is faster than human's reaction for a single click.Liability

© 2022 - 2024 — McMap. All rights reserved.