Detecting horizontal mouse motion with Glut/OpenGL - opengl

I'm trying to detect horizontal mouse motion with OpenGL, so, when detected, execute a glutPostRedisplay(). Problem is that scene is also redrawed on vertical mouse movement.
This is the code of the registered callbacks (note mouse_inix and mouse_iniy are global (double) variables):
void mouse(int button, int state, int x, int y)
{
if (state == GLUT_DOWN) {
mouse_inix = (double)x;
mouse_iniy = (double)y;
}
}
void motion(int x, int y)
{
if (((double)x) != mouse_inix) {
angle += 20.0;
glutPostRedisplay();
}
}

Are you sure? It doesn't look like from the code you've posted that vertical mouse movement will trigger the glutPostRedisplay() call.
BUT, you've defined "horizontal mouse movement" very narrowly here. If you move the mouse up and down, you're almost sure to get a few pixels of horizontal movement. Maybe you could put a dead zone around the mouse to keep it from moving on every pixel. Something like:
void motion(int x, int y)
{
if ((abs(x - (int)mouse_inix) > 10) {
angle += 20.0;
glutPostRedisplay();
}
}
That's one thing that's going on here. Another is the use of "double". Since glut is returning mouse coordinates as ints, you're better off sticking with that. Trying to compare "(double)x != mouse_inix" will almost certainly be true because of the precision issues with doubles. You generally don't want to compare for exactly equal to or not equal to using floating point numbers. The use of the dead zone will negate that issue, but still, why convert to doubles if you don't need them?
I don't know if "20" is degrees or radians, but it could result in some pretty jumpy moves either way. Consider scaling the size of the move to the size of the mouse move:
void motion(int x, int y)
{
int deltaX = (abs(x - (int)mouse_inix);
if (deltaX > 10) {
angle += (double)deltaX; // or "deltaX/scaleFactor" to make it move more/less
glutPostRedisplay();
}
}
It will still only rotate one way. If you used the sign of "deltaX", you would be able to rotated both directions depending on how you moved the mouse.

Related

OpenGL draw circle with Mouse Move

I am trying to use the function mouseMove(int x, int y) to draw a circle centered at my mouse as I click and drag it across the screen. Circles will be drawn on the moving mouse like a spray paint. So far, this is what I have
void mouseMove(int x, int y) {
glBegin(GL_POLYGON);
for (int i = 0; i <= 360; i++)
{
float theta = (2 * 3.14 * i) / 360;
glVertex2f((size/2 + x) * cos(theta), (size/2 + y) * sin(theta));
}
glEnd();
glutPostRedisplay();
}
But when using this, it draws very large circles that aren't centered around my mouse. How would I alter this to make the program draw circles centered at my mouse?
To describe the project, I am creating a painting program that changes shapes, colors, sizes, and rotations of the drawing done in mouseMove. For now, the size is an int set to 32. When the user selects the shape using the 'b' key in a keyboard function, he/she can switch the shapes that are drawn around the mouse as the user clicks and drags the mouse around. Like a spray paint. All the other shapes work shaped around the mouse except for the circle shape spray.
This answer assumes that things like your viewport and projection matrices are set up correctly, and that the input to this function is taking into account the fact that "screen coordinates" (what the mouse uses) are not the same thing as "OpenGL Coordinate Space" (this usually implies reversing the direction of the y-axis for one or the other).
The math you're using for setting your vertex coordinates is wrong. The mouse's x and y coordinates should not be multiplied by the sine/cosine functions.
The correct way to write it is
glVertex2f((size/2) * cos(theta) + x, (size/2) * sin(theta) + y);
I would also add that you appear to still be using OpenGL's Immediate Mode rendering, which is Deprecated and will offer extremely poor training for a professional setting. I highly advise you learn Modern OpenGL (3.x+) and reapply those concepts to whatever projects you're already working on. This is a very good tutorial.

C++ how to drag bitmap around screen

Hi so I'm trying to make it so a little UFO bitmap (drawing/painting already taken care of) can be dragged around the screen. I can't seem to make the UFO position update and then redraw repeatedly from the MouseButtonDown() function (simplified code for mouse event handler). Any suggestions on detecting the dragging and redrawing accordingly? Code is below for relevant functions:
void MouseButtonDown(int x, int y, BOOL bLeft)
{
if (bLeft)
{
while(_bMouseMoving == true && _bMouseDragRelease == false) {
_iSaucerX = x - (_pSaucer->GetWidth() / 2);
_iSaucerY = y - (_pSaucer->GetHeight() / 2);
InvalidateRect(_pGame->GetWindow(), NULL, FALSE);
}
// Set the saucer position to the mouse position
_iSaucerX = x - (_pSaucer->GetWidth() / 2);
_iSaucerY = y - (_pSaucer->GetHeight() / 2);
}
else
{
// Stop the saucer
_iSpeedX = 0;
_iSpeedY = 0;
}
}
void MouseButtonUp(int x, int y, BOOL bLeft)
{
_bMouseDragRelease = true;
}
void MouseMove(int x, int y)
{
_bMouseMoving = true;
}
To clarify what chris said, you're only going to get the WM_xBUTTONDOWN message once, and you'll need to use that to toggle a dragging state that you can query when you recieve a WM_MOUSEMOVE message.
When you get the mouse move message during a dragging state, you'll want to invalidate the rectangle surrounding where the ufo was, and the rectangle surrounding where it is.
Invalidating a rectangle causes WM_PAINT messages, where you redraw whatever was behind the ufo, and the ufo in it's new place.
Or you could cheat and make the UFO a cursor when you're dragging :)

Using glut to prevent the mouse from leaving the window

I'm using glut for a game right now and I'm trying to keep the mouse inside the window. This isn't a first person shooter so locking it in the center is no good. I already know about glutWarpPointer(int, int); and I've trying things that work (kinda).
I've tried having the mouse warp back to the nearest edge of the window when it leaves, this works, but for a split second you see the mouse outside of the window and teleport back in. I don't want that, I want it to seem like the mouse just hits the edge of the window and stops going any further in that direction, while keeping movement in any other available direction. Like you would expect it to work.
This is not exactly an answer to your question, but it is an answer to your problem!
Almost every game has its own cursors. They would hide the mouse, and draw the cursor manually where the mouse should be positioned.
If you get your own cursor image and do as I said, you can simply draw the curser at the edge of the screen, even though the mouse position reads out of boundaries. Then you can warp the mouse back in.
Tried to search and figure this out and couldn't find an answer, so I implemented it myself. Here is what worked for my first person camera case:
callback from glutPassiveMotion
CODE SAMPLE
void Game::passiveMouseMotion(int x, int y)
{
//of my code for doing the cam, yours is may be different, this is based on the example from https://learnopengl.com/Getting-started/Camera
if (firstMouse) {
lastX = x;
lastY = y;
firstMouse = false;
}
float xoffset = x - lastX;
float yoffset = lastY - y; // reversed since y-coordinates go from bottom to top
lastX = x;
lastY = y;
camera->ProcessMouseMovement(xoffset, yoffset);
glutPostRedisplay();
//this is the main thing that keeps it from leaving the screen
if ( x < 100 || x > win_w - 100 ) { //you can use values other than 100 for the screen edges if you like, kind of seems to depend on your mouse sensitivity for what ends up working best
lastX = win_w/2; //centers the last known position, this way there isn't an odd jump with your cam as it resets
lastY = win_h/2;
glutWarpPointer(win_w/2, win_h/2); //centers the cursor
} else if (y < 100 || y > win_h - 100) {
lastX = win_w/2;
lastY = win_h/2;
glutWarpPointer(win_w/2, win_h/2);
}
}
Hope this helps!

How do I make projectiles?

I am totally stumped on this one. I'm using C++ and SFML 1.6 for a game I'm developing, and I have no bloody idea. How do I make projectiles (like bullets)? I just don't understand it. It could be my lack of sleep but I don't know.
So my question is how do I create a Sprite that moves in a definite direction based on where the mouse is? (Think of a top down shooter with mouse aiming)
Easiest solution:
If the mouse is at Mx,My and the ship is at Sx,Sy then calculate the direction from the ship to the mouse:
Dx=Sx-Mx
Dy=Sy-My
Now normalise D (this means scale it so that it's length is one):
DLen=sqrt(Dx*Dx + Dy*Dy)
Dx/=DLen;
Dy/=DLen;
Now Dx is the distance you want to move the bullet on the x axis in order to get bullet speed of 1.
Thus each frame you move the bullet like so (position of bullet: Bx,By Speed of bullet: Bs [in pixels per millisec] Frame time Ft[in millisec])
Bx=Bx+Dx*Bs*Ft
By=By+Dy*Bs*Ft
This give you a bullet that moves towards the mouse position at a speed independent of the direction of the mouse or framerate of the game.
EDIT: As #MSalters says you need to check for the DLen==0 case when the mouse is directly above the ship to avoid division by zero errors on the normalise
One way to do it is to make the bullet face the mouse and then move it across the x and y axis by using trigonometry to find the hypotinuse from the angle. I don't think i explained this very well, so here the code to make a sprite move from its rotation:
void sMove(sf::Sprite& input,float toMove, int rotation){
bool negY = false;
bool negX = false;
int newRot = rotation;
if (rotation <= 90){
negY = true;
}
else if (rotation <= 180){
//newRot -= 90;
negY = true;
}
else if (rotation <= 360){
newRot -= 270;
negY = true;
negX = true;
}
float y = toMove*cos(newRot*PI/180);
float x = toMove*sin(newRot*PI/180);
if (negY){
y = y*-1;
}
if (negX){
x = x*-1
}
input.move(x, y);
}

Trapping the mouse?

I'm using GLUT and developing a FPS game. I need a way to trap the mouse so that the camera continues to move because right now when the mouse position exceeds the monitor limit, there is no way to calculate change in X or change in Y. How can I 'trap' the mouse with GLUT?
Thanks
I'd recommend using a ready-made engine like OGRE 3D instead, but if you really want to reinvent the wheel, here's how...
In all cases I'm aware of, PC FPS games "trap" the pointer by registering a mouse motion callback, noting the relative motion, and then warping the pointer back to the center of the window.
Here's some code I wrote to add mouse input to a sample ping-pong table in an OpenGL with C++ course a year or two ago:
void resetPointer() {
glutWarpPointer(TABLE_X/2, TABLE_Y/2);
lastMousePos = TABLE_Y/2;
}
void mouseFunc(int sx, int sy) {
if (!started) { return; }
int vertMotion = lastMousePos - sy;
lastMousePos = sy;
player1.move(vertMotion);
// Keep the pointer from leaving the window.
if (fabs(TABLE_X/2 - sx) > 25 || fabs(TABLE_Y/2 - sy) > 25) {
resetPointer();
}
}
// This goes in with your "start new game" code if you want a menu
resetPointer();
glutSetCursor(GLUT_CURSOR_NONE);
glutPassiveMotionFunc(mouseFunc);
It only tracks vertical motion, but adding horizontal is trivial.