Computer graphics to achieve mouse drag primitives
Problem description
When it is necessary to drag primitives in computer graphics, the key is how to judge whether the mouse is dragging and the movement of the mouse when it is dragged
- Determines whether the mouse is pressed inside the element or moved inside the element
- Confirm the movement of the mouse, click the element, and the origin (anchor point) of the element will not blink to the position of the cursor
The following variables are known
bool isContained reflects whether the current position of the mouse is inside the element. true means inside the element and false means outside the element
Bool isdragging reflects whether the mouse is pressed at this time. true indicates that the mouse is pressed at this time, and false indicates that the mouse is not pressed at this time
Primitive primitive structure with color and position members
Solution
Question one
For the first question, we can find that the mouse has the following three states
-
Mouse release
-
Press the mouse and the mouse is outside the element
-
Press the mouse and the mouse is inside the element
What we need to do is to distinguish these three states. We can use an int variable p to represent these three states with 0, 1 and 2 respectively. The key is how to convert these three states
0 → 1: when the mouse is pressed (isdragging), the mouse is in the element (isContained), and the mouse is released at the moment (p == 0)
0 → 2: when the mouse is pressed (isdragging), the mouse is not in the element (! isContained), and the mouse is released at the last moment (p == 0)
1 → 0, 2 → 0: when the mouse is released (! Isdragging)
This part of the code is as follows:
//Using the static variable allows p to initialize only once in a loop static int p = 0; if (isDraging) { if (isContained) { if (p == 0) p = 1; } else { if (p == 0) p = 2; } } else { p = 0; }
Question two
For the second problem, we need to find the displacement during the movement of the mouse. We cannot directly assign the NDC coordinate of the mouse to the coordinate of the element (this will cause the element to jump to the mouse position immediately when the mouse is pressed in the element), Instead, the displacement vector coordinates from the coordinates of the moment when the mouse starts dragging to the coordinates of the mouse at this time plus the coordinates of the previous time of the element in the figure above should be assigned to the coordinates of the element at this time
The details are as follows:
As shown in the following figure, the mouse moves from B to D, and the element moves from A to C
p when the status is 0 → 1, record the mouse coordinate B, entity position A and calculate A B → \overrightarrow{AB} AB
When p is in state 1, it means that the element is being dragged. The mouse coordinate is D and the element coordinate is C. at this time, the element coordinate is updated, that is C spot sit mark = D spot sit mark − A B → Point C coordinate = point D coordinate - \ overrightarrow{AB} Coordinate of point C = coordinate of point D − AB
The code is implemented as follows
Note: the csugl namespace is created by yourself. You can refer to the logic implementation. After understanding the solution to the problem, you can write it yourself
void MouseDragger(const glm::ivec2 &winSize, csugl::Ref<Primitive> primitive) { // Mouse inside element static bool isContained = false; // The mouse is being pressed static bool isDraging = false; // Is the drag process started static bool flag = false; // Mouse displacement difference static glm::vec2 changeCurNDCpos = {0.0f, 0.0f}; // 1. Obtain mouse window coordinates: // 2. Convert to NDC coordinates: (use WindowPosToNDCPos to convert) // 3. Whether dragging: // 4. Whether it is in the element: (use primitive's is_contained detection) // 5. Set element color: // 6. Set the new coordinates of the element: float xPos, yPos; xPos = csugl::Input::GetMousePosX(); yPos = csugl::Input::GetMousePosY(); glm::vec2 curpos = {xPos, yPos}; glm::vec2 curNDCpos = WindowPosToNDCPos(curpos, winSize); isDraging = csugl::Input::IsMouseButtonPressed(csugl::Mouse::Button0); isContained = primitive->is_contained(curNDCpos); //The variable p is used to determine whether to click the mouse in the element. 0 indicates that the mouse is released, 1 indicates that the mouse is pressed and inside the element, and 2 indicates that the mouse is pressed and outside the element static int p = 0; if (isDraging) { if (isContained) { if (p == 0) { changeCurNDCpos = curNDCpos - primitive->position; p = 1; } } else { if (p == 0) { p = 2; } } } else { p = 0; } if(p==1) { primitive->color = {0.1f, 0.5f, 0.8f}; primitive->position = curNDCpos - changeCurNDCpos; } else { primitive->color = {0.8f, 0.5f, 0.1f}; } } // Convert window coordinates to standard device coordinates (NDC) glm::vec2 WindowPosToNDCPos(const glm::vec2 &winPosition, const glm::vec2 &winSize) { glm::vec2 tmpPos = winPosition / winSize * 2.0f - 1.0f; //Convert to float solution tmpPos.y = -tmpPos.y;//The coordinates are opposite up and down return tmpPos; }