SFML community forums

Help => Window => Topic started by: tntexplosivesltd on December 27, 2010, 06:10:17 am

Title: sf::Sleep problem and mouse input problem.
Post by: tntexplosivesltd on December 27, 2010, 06:10:17 am
I have a bit of a problem, stemming from this code:
Code: [Select]
while (App->IsOpened())
    {
        sf::Sleep(0.001);
        // Process all "application" events
        sf::Event Event;
        while (App->GetEvent(Event))
        {
            // Close window : exit
            if (Event.Type == sf::Event::Closed)
                App->Close();

            // Escape key : exit
            if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
                App->Close();

            // Resize event : adjust viewport
            if (Event.Type == sf::Event::Resized)
                glViewport(0, 0, Event.Size.Width, Event.Size.Height);

            /*
            if (Event.Key.Code == sf::Key::F1)
            {
                sf::Image Screen = App->Capture();
                Screen.SaveToFile("screenshot.jpg");
            }
            */
        }

        cout << "" << 1/App->GetFrameTime() << endl;
        moving = false;
        // adjust x- y- and z- step amounts based on current direction/view rotation
        xStep = playerSpeed * sin((PI * zRotation) / 180);
        yStep = playerSpeed * cos((PI * zRotation) / 180);
        zStep = -playerSpeed * sin((PI * rotation) / 180);
        //cout << "zRot: " << zRotation << " rot: " << rotation << endl;

        // process real-time input
        if (Input.IsKeyDown(sf::Key::W))    // W = forwards
        {
            moving = true;
            playerX -= (xStep * cos((PI * rotation) / 180));
            playerY -= (yStep * cos((PI * rotation) / 180));
            playerZ -= zStep;
        }

        if (Input.IsKeyDown(sf::Key::S))    // S = backwards
        {
            moving = true;
            playerX += (xStep * cos((PI * rotation) / 180));
            playerY += (yStep * cos((PI * rotation) / 180));
            playerZ += zStep;
        }

        if (Input.IsKeyDown(sf::Key::A))    //A = strafe left
        {
            if ((moving = true))
            {
                xStep *= 0.707106;
                yStep *= 0.707106;
            }
            playerX += yStep;
            playerY -= xStep;
        }

        if (Input.IsKeyDown(sf::Key::D))    //D = strafe right
        {
            if ((moving = true))
            {
                xStep *= 0.707106;
                yStep *= 0.707106;
            }
            playerX -= yStep;
            playerY += xStep;
        }
        // Rotate view based on mouse movement
        mouseDeltaX = Input.GetMouseX() - centreX;
        mouseDeltaY = Input.GetMouseY() - centreY;
        zRotation += (mouseDeltaX / 10);
        rotation += (mouseDeltaY / 10);
        //cout << "DeltaX: " << mouseDeltaX << " DeltaY: " << mouseDeltaY << endl;

        // Z rotation normalisation - between 0 and 360
        if (zRotation >= 360)
        {
            zRotation -= 360;
        }

        if (zRotation < 0)
        {
            zRotation += 360;
        }

        // X/Y rotation limits
        if (rotation < -90)
        {
            rotation = -90;
        }
        if (rotation >= 90)
        {
            rotation = 90;
        }


        // Set the active window before using OpenGL commands
        // It's useless here because active window is always the same,
        // but don't forget it if you use multiple windows or controls
        App->SetActive();

        //  color and depth buffer
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        // Rotate the view first
        glRotatef(-90 + rotation, 1.f, 0.f, 0.f);
        glRotatef(zRotation, 0.f, 0.f, 1.f);

        // Then translate it
        glTranslatef(playerX, playerY, playerZ);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glCallList(ALL_CUBES);
        glFlush();

        App->Display();
        App->SetCursorPosition(centreX, centreY);
    }
    return EXIT_SUCCESS;
}


What is happening is when I have the sf::Sleep(0.001) in there, the framerate drops to ~60FPS. When I comment it out, it shoots up to ~300-400FPS. Even if it's drawing only one block, the FPS is ~60FPS with sf::Sleep(0.001). This is weird.

Additionally, I still have the same problem listed in this thread (http://www.sfml-dev.org/forum/viewtopic.php?t=3753), with the mouse input.

So I have a few questions:
1) What is happening with the framerate varying so much?
2) What is the difference between Input.GetMouseX() and Event.MouseMoved.X?
Title: sf::Sleep problem and mouse input problem.
Post by: Laurent on December 27, 2010, 08:05:46 am
Quote
1) What is happening with the framerate varying so much?

What's your OS?

Quote
2) What is the difference between Input.GetMouseX() and Event.MouseMoved.X?

There's none. The first one is always available, the second one is given when you receive a MouseMoved event.
Title: sf::Sleep problem and mouse input problem.
Post by: tntexplosivesltd on December 27, 2010, 08:49:38 am
I'm using Windows 7 32-bit, and Arch Linux X86_64, and getting the same problem on both operating systems :(
Title: sf::Sleep problem and mouse input problem.
Post by: Laurent on December 27, 2010, 09:12:01 am
Thread schedulers in common OSes usually have a time quantum of approx. 16 ms (ie. once a thread goes to bed, it can only wake up after a minimum of 16 ms). And 16ms = 1/0.016 Hz = approx. 60Hz. That could be an explanation.
Title: sf::Sleep problem and mouse input problem.
Post by: tntexplosivesltd on December 27, 2010, 09:41:55 am
Okay, thanks.
I changed from Input.GetMouseX() to Event.MouseMove.X, and it hasn't changed how the mouse behaves under Windows 7, as outlined in my other thread. I put the sf::Sleep(0.005) in there because it seemed to fix it, but it drags the FPS down to ~60FPS. How can I fix this? Will it improve if I put the rendering in a thread on its own, and everything else in a second thread?
Title: sf::Sleep problem and mouse input problem.
Post by: Laurent on December 27, 2010, 09:48:24 am
Quote
How can I fix this?

Seriously, I don't understand why you get these problems with mouse input.
But is it such a bad workaround? I mean, 60 FPS should be enough.

Quote
Will it improve if I put the rendering in a thread on its own, and everything else in a second thread?

I don't know, it depends on the origin of your problem. But you can try.
Title: sf::Sleep problem and mouse input problem.
Post by: model76 on December 27, 2010, 12:13:42 pm
Quote from: "Laurent"
Quote
2) What is the difference between Input.GetMouseX() and Event.MouseMoved.X?

There's none. The first one is always available, the second one is given when you receive a MouseMoved event.
This is not true in SFML 1.6, because Input and Event aren't synchronized. So there are situations where Input.GetMouseX() is not equal to Event.MouseMoved.X.
Title: sf::Sleep problem and mouse input problem.
Post by: Laurent on December 27, 2010, 12:24:27 pm
Quote
This is not true in SFML 1.6, because Input and Event aren't synchronized. So there are situations where Input.GetMouseX() is not equal to Event.MouseMoved.X.

Right. However this is a detail, at worst sf::Input will get delayed by one frame. So it can't explain the problems that we're talking about.
Title: sf::Sleep problem and mouse input problem.
Post by: tntexplosivesltd on December 27, 2010, 11:29:13 pm
Has anyone ever had this problem before? It seems a bit odd.
Title: sf::Sleep problem and mouse input problem.
Post by: model76 on December 28, 2010, 03:20:14 am
If you create a test program in a single file, I will happily compile and run it on my computer. Well, if you are using 1.6, that is...
Title: sf::Sleep problem and mouse input problem.
Post by: tntexplosivesltd on December 28, 2010, 05:26:25 am
Finally fixed it. I looked back at one of my previous snapshots and found that if I moved App->SetCursorPosition(centreX, centreY); from after App->Display(); to just before I take mouse input:
Code: [Select]
App->SetCursorPosition(centreX, centreY);
mouseDeltaX = Input.GetMouseX() - centreX;
mouseDeltaY = Input.GetMouseY() - centreY;
zRotation += (mouseDeltaX / 10);
rotation += (mouseDeltaY / 10);

it works fine. Yay!
On a side note, why does this change it?
Title: sf::Sleep problem and mouse input problem.
Post by: model76 on December 29, 2010, 02:18:48 am
I don't have an answer to your question, but I would suggest that you make the following changes to your program:

Move the cursor position/rotation stuff to the event loop, and only do the calculations if the cursor has moved.

Also, make the rotation speed independent of the application speed, by dividing the rotation amount by the frame delta time, instead of some constant.

Pseudo code:
Code: [Select]
if( Event.Type == MouseMove )
{
    if( centreX != Event.MouseMoved.X )
        zRotation += (Event.MouseMoved.X - centreX) / frameTime;

    if( centreY != Event.MouseMoved.Y )
        rotation += (Event.MouseMoved.Y - centreY) / frameTime;

    App->SetCursorPosition(centreX, centreY);
}


If you haven't already, I still think you should take a gander at that game loop article I linked to in the other thread.
Here is the link again for good measure:  http://www.koonsolo.com/news/dewitters-gameloop/

You might enjoy it - I did!
Wonderful bedtime reading. :)
Title: sf::Sleep problem and mouse input problem.
Post by: tntexplosivesltd on December 29, 2010, 05:44:53 am
Okay thanks for that.
I tried scaling the mouse movement by the frame time, but the view moves less when the frame rate is lower. Not sure if this is expected?
Title: sf::Sleep problem and mouse input problem.
Post by: model76 on December 29, 2010, 05:54:47 am
Um, no. Ignore the frame time thing, that was just me not thinking clearly. Sorry  :oops: