SFML community forums

Help => General => Topic started by: grok on January 20, 2015, 11:59:34 am

Title: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 20, 2015, 11:59:34 am
Hello.

I use SFML 2.2 from the github repo (the current version).
I program a 2d prototype game (2d mario style where the camera follows the player) , and am experiencing the buggy imagery during rendering, for example a chunk of vertex array blocks are misplaced which gives an awful visual/glitches. I've read several game-related articles regarding game loop, time step, etc and I *do* understand what's going on, but cannot spot the bug.

What I do: perform scene updates with fixed UPDATE_STEP value (it then gets used when calculating, for example, the Player's new position, being applied to the velocity, etc).
Then I use the remained slice of time since the last update divided by UPDATE_STEP as a ratio (0..1) to perform the interpolation during rendering.

Basically I update the position of my Player and calibrate the Camera accordingly, all the rest of the game scene (tile map represented as a vertex array) remains untouched.

Could you help me to figure out where's my mistake?
Here we go:

void gameLoop() {
    const sf::Time UPDATE_STEP = sf::seconds(1.0f / 120.0f);
    sf::Time timeSinceLastUpdate = sf::Time::Zero;
    _renderWindow.setFramerateLimit(60);
    sf::Clock clock;

    while (_renderWindow.isOpen()) {

        sf::Event event;
        while (_renderWindow.pollEvent(event)) {
         
            _curGameScene->processEvent(event);
           
            switch (event.type) {
            case sf::Event::KeyPressed:
                switch (event.key.code) {
                case sf::Keyboard::Escape:                
                    _renderWindow.close();
                    break;                
                default:
                    break;
                }
                break;
            case sf::Event::Closed:
                _renderWindow.close();
                break;
            default:
                break;
            }
        }

                _curGameScene->processKeyboard();

                sf::Time dt = clock.restart();
                timeSinceLastUpdate += dt;
               
                if (timeSinceLastUpdate > sf::seconds(0.25)) {
                        timeSinceLastUpdate = sf::seconds(0.25);
                }

                while (timeSinceLastUpdate >= UPDATE_STEP) {

                        _curGameScene->update(UPDATE_STEP.asSeconds());
                        timeSinceLastUpdate -= UPDATE_STEP;
                }

        //RATIO FOR INTERPOLATION DURING RENDER
        const float alpha = timeSinceLastUpdate.asSeconds() / UPDATE_STEP.asSeconds();
       
        //normal draw
        _renderWindow.setView(_renderWindow.getDefaultView());
        _curGameScene->render(_renderWindow, sf::RenderStates::Default, alpha);
       
        //ortho draw
        _renderWindow.setView(_renderWindow.getDefaultView());
        _renderWindow.draw(infoText);
        _curGameScene->renderOrtho(_renderWindow);

        _renderWindow.display();
    }
}
 

my _curGameScene has the player sprite entity, the camera, which follows him, and the tile map (implemented as a vertex array).
so, in the update() method I do:
void LevelScene::update(float dtExpandedInSeconds) {

    _player->update(dtExpandedInSeconds);      
}
 

player's update method is as follows:
virtual void update(float dtExpandedInSeconds) {
       
    //store the previous position of the sprite
    _prevPos = _pos;

    //calculate the new position of the sprite
    _pos.x = _pos.x + _vxy.x*dtExpandedInSeconds;
}
 

then when we invoke the LevelScene's render method:
void LevelScene::render(sf::RenderTarget &target, sf::RenderStates renderStates, float ratio) {

    //CALCULATED POSITION OF THE CAMERA TAKING INTO ACCOUNT THE RENDER RATIO
    const sf::Vector2f viewCenter = _camera->calcPos(ratio);

    sf::View view = target.getView();
    if (_useZoom) {
        view.zoom(0.5);
    }
    view.setCenter(viewCenter);
    target.setView(view);
    target.clear(_bgColor);

    _tileMap->render(target, renderStates, ratio);
    _player->render(target, renderStates, ratio);
}
 

which involves the Camera's calcPos method:
const sf::Vector2f &calcPos(float ratio) {

    sf::Vector2f followPos = _sprite2Follow->getPos();
    sf::Vector2f followPrevPos = _sprite2Follow->getPrevPos();

    //HERE COMES THE INTERPOLATION
    _calcPos.x = followPrevPos.x*ratio + followPos.x*(1.0-ratio);
    _calcPos.y = followPrevPos.y*ratio + followPos.y*(1.0-ratio);

    if (_calcPos.x <= _halfViewWH.x) {
        _calcPos.x = 0;
    } else if (_calcPos.x <= _mapWH.x - _halfViewWH.x) {
        _calcPos.x = _calcPos.x - _halfViewWH.x;
    } else {
        _calcPos.x = _mapWH.x - _viewWH.x;
    }

    if (_calcPos.y <= _halfViewWH.y) {
        _calcPos.y = 0;
    } else if (_calcPos.y <= _mapWH.y - _halfViewWH.y) {
        _calcPos.y = _calcPos.y - _halfViewWH.y;
    } else {
        _calcPos.y = _mapWH.y - _viewWH.y;
    }

    _calcPos.x += _halfViewWH.x;
    _calcPos.y += _halfViewWH.y;

    return _calcPos;
}
 

The Player's render method:
virtual void render(sf::RenderTarget &target, sf::RenderStates renderStates, float ratio) {

    _sprite.setPosition(_prevPos.x*ratio + _pos.x*(1.0-ratio), _prevPos.y*ratio + _pos.y*(1.0-ratio));
    target.draw(_sprite, renderStates);
}
 

I have been debugging half a day but the bug is still here. Maybe you have some ideas about what is wrong with my approach? Thank you.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 20, 2015, 01:32:38 pm
UPDATED: I have slightly better results when I do not take the remained part of time slice into consideration and perform an additional update with that part, i.e.:

void gameLoop() {

    //... as above

    _curGameScene->processKeyboard();

    sf::Time dt = clock.restart();
    timeSinceLastUpdate += dt;

    if (timeSinceLastUpdate > sf::seconds(0.25)) {
        timeSinceLastUpdate = sf::seconds(0.25);
    }

    while (timeSinceLastUpdate >= UPDATE_STEP) {

        _curGameScene->update(UPDATE_STEP.asSeconds());
        timeSinceLastUpdate -= UPDATE_STEP;
        ++updatesCnt;
    }

    //ADDED
    _curGameScene->update(timeSinceLastUpdate.asSeconds());
    timeSinceLastUpdate = sf::Time::Zero;

    _renderWindow.setView(_renderWindow.getDefaultView());
    _curGameScene->render(_renderWindow, sf::RenderStates::Default); //NO ALPHA IS PASSED
    //ortho draw
    _renderWindow.setView(_renderWindow.getDefaultView());
    _renderWindow.draw(infoText);
    _curGameScene->renderOrtho(_renderWindow);
    //
}
 
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: Hapax on January 20, 2015, 03:00:42 pm
Just to warn you, you're likely to hear "complete and minimal example (http://en.sfml-dev.org/forums/index.php?topic=5559.msg36368#msg36368)" soon. It's very unlikely that someone is going to look through all of this and follow how its all linked etc.. Maybe someone will get bored or fancy a challenge. You may be in luck; who knows?

However, going by your description, it's possible that the "glitches" are because your tiles are not being positioned at integer locations. This reduces smoothness in motion, though, so it's a trade-off.
A screenshot/video of the glitch would help us to know what problem is looking to be solved, especially if it's not what I just described.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 20, 2015, 04:59:19 pm
Thanks for the reply, but no, it didn't help. I rechecked that the coodinates are integral (they're floats, but rounded, like: 32.0, 64.0, etc).

As for complete and minimal example, here it is:
#include <iostream>

#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/System/Clock.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/System/Vector2.hpp>

enum E_MOVE_TYPE {
    LEFT, RIGHT, IDLE
};

struct Entity {
    sf::RectangleShape shape;
    sf::Vector2f pos;
    sf::Vector2f prevPos;
    bool moveKeyHold;
    E_MOVE_TYPE stepX;
    sf::Vector2f accxy, vxy, maxVxy;

    void update(float dt) {

        //save the previous pos
        prevPos = pos;

        if (moveKeyHold) {
            float accX = accxy.x * dt;
            if (stepX == E_MOVE_TYPE::RIGHT) {
                vxy.x += accX;
            } else if (stepX == E_MOVE_TYPE::LEFT) {
                vxy.x -= accX;
            }
        } else {
            float accX = accxy.x * dt;
            if (vxy.x > 0) {
                vxy.x -= accX;
                if (vxy.x < 0) {
                    vxy.x = 0;
                }
            } else if (vxy.x < 0) {
                vxy.x += accX;
                if (vxy.x > 0) {
                    vxy.x = 0;
                }
            }
        }

        if (vxy.x > maxVxy.x) {
            vxy.x = maxVxy.x;
        } else if (vxy.x < -maxVxy.x) {
            vxy.x = - maxVxy.x;
        }

        //update the current position
        pos.x = pos.x + vxy.x*dt;
    }

    void render(sf::RenderWindow *window, sf::RenderStates states, float ratio) {
        shape.setPosition(pos.x*ratio + prevPos.x*(1.0-ratio), pos.y*ratio + prevPos.y*(1.0-ratio));
        window->draw(shape, states);
    }
};

struct Camera {
    Entity *player;
    sf::Vector2f viewWH, halfViewWH;
    sf::Vector2u mapWH;
    sf::Vector2u screenWH;

    sf::Vector2f calcPos(float ratio) {

        sf::Vector2f followPos = player->pos;
        sf::Vector2f followPrevPos = player->prevPos;

        sf::Vector2f result;

        result.x = followPos.x*ratio + followPrevPos.x*(1.0f-ratio);
        result.y = followPos.y*ratio + followPrevPos.y*(1.0f-ratio);

        if (result.x <= halfViewWH.x) {
            result.x = 0;
        } else if (result.x <= mapWH.x - halfViewWH.x) {
            result.x = result.x - halfViewWH.x;
        } else {
            result.x = mapWH.x - viewWH.x;
        }

        if (result.y <= halfViewWH.y) {
            result.y = 0;
        } else if (result.y <= mapWH.y - halfViewWH.y) {
            result.y = result.y - halfViewWH.y;
        } else {
            result.y = mapWH.y - viewWH.y;
        }

        result.x += halfViewWH.x;
        result.y += halfViewWH.y;

        return result;
    }
};

//GLOBAL VARIABLES
Entity player;
Camera camera;
sf::VertexArray *pTileMap;

////////
void updateLogic(float dt) {
    player.update(dt);
}

void render(sf::RenderWindow *window, float ratio) {

    sf::Vector2f viewCenter = camera.calcPos(ratio);
    sf::View view = window->getView();
    view.setCenter(viewCenter);
    window->setView(view);

    window->clear(sf::Color::Black);
    window->draw(*pTileMap, sf::RenderStates::Default);
    player.render(window, sf::RenderStates::Default, ratio);
}

void initializeTileMap(const sf::Vector2u &levelWH) {

    int maxX = int(levelWH.x/32) - 1;
    int maxY = int(levelWH.y/32) - 1;

    pTileMap = new sf::VertexArray();
    pTileMap->setPrimitiveType(sf::PrimitiveType::Quads);

    bool isYellowColor = false;
    for (int y = 0; y <= maxY; ++y) {
        for (int x = 0; x <= maxX; ++x) {
            if ((y >= 1 && x <= 50) || (x >= 60 && x <= 70 && y >= 20 && y <= 120) || (x == maxX)) {
                 sf::Vertex v;

                 v.position = sf::Vector2f {static_cast<float>(x * 32), static_cast<float>(levelWH.y - (y+1)*32)};
                 v.color = isYellowColor ? sf::Color::Yellow : sf::Color::Green;
                 pTileMap->append(v);

                 v.position = sf::Vector2f {static_cast<float>(x * 32), static_cast<float>(levelWH.y - (y)*32)};
                 v.color = isYellowColor ? sf::Color::Yellow : sf::Color::Green;
                 pTileMap->append(v);

                 v.position =  sf::Vector2f {static_cast<float>((x + 1) * 32), static_cast<float>(levelWH.y - (y)*32)};
                 v.color = isYellowColor ? sf::Color::Yellow : sf::Color::Green;
                 pTileMap->append(v);

                 v.position = sf::Vector2f {static_cast<float>((x + 1) * 32), static_cast<float>(levelWH.y - (y+1)*32)};
                 v.color = isYellowColor ? sf::Color::Yellow : sf::Color::Green;
                 pTileMap->append(v);

                 isYellowColor = !isYellowColor;
            }
        }
    }
}

void deallocateTileMap() {
    delete pTileMap;
}

void gameLoop(sf::RenderWindow *window) {

    const sf::Time UPDATE_STEP = sf::seconds(1.0f / 120.0f);
    sf::Time timeSinceLastUpdate = sf::Time::Zero;

    sf::Clock clock;
    while (window->isOpen()) {
        sf::Event event;
        while (window->pollEvent(event)) {
            switch (event.type) {
            case sf::Event::KeyPressed:
                switch (event.key.code) {
                case sf::Keyboard::Escape:
                    window->close();
                    break;
                case sf::Keyboard::Left:
                    player.moveKeyHold = true;
                    player.stepX = E_MOVE_TYPE::LEFT;
                    break;
                case sf::Keyboard::Right:
                    player.moveKeyHold = true;
                    player.stepX = E_MOVE_TYPE::RIGHT;
                    break;
                default:
                    break;
                }
                break;
            case sf::Event::KeyReleased:
                player.moveKeyHold = false;
                player.stepX = E_MOVE_TYPE::IDLE;
                break;
            case sf::Event::Closed:
                window->close();
                break;
            default:
                break;
            }
        }

        //update logic
        sf::Time dt = clock.restart();
        timeSinceLastUpdate += dt;

        if (timeSinceLastUpdate > sf::seconds(0.25)) {
            timeSinceLastUpdate = sf::seconds(0.25);
        }

        while (timeSinceLastUpdate >= UPDATE_STEP) {
            updateLogic(UPDATE_STEP.asSeconds());
            timeSinceLastUpdate -= UPDATE_STEP;
        }

        const float alpha = timeSinceLastUpdate.asSeconds() / UPDATE_STEP.asSeconds();

        //draw logic
        render(window, alpha);

        //display now!
        window->display();
    }
}

int main() {

    sf::RenderWindow window;
    sf::VideoMode videoMode = sf::VideoMode::getDesktopMode();

    window.create(videoMode, "test smooth movement", sf::Style::Default, sf::ContextSettings {});
    window.setFramerateLimit(60);

    sf::Vector2u levelWH(1024*3, videoMode.height);

    player.pos.x = 1000;
    player.pos.y = 400;
    player.prevPos = player.pos;
    player.moveKeyHold = false;
    player.stepX = E_MOVE_TYPE::IDLE;
    player.shape.setSize(sf::Vector2f(40, 40));
    player.shape.setPosition(player.pos);
    player.shape.setFillColor(sf::Color::Red);
    player.vxy = sf::Vector2f(50, 0);
    player.accxy = sf::Vector2f(200, 0);
    player.maxVxy = sf::Vector2f(700, 225);

    sf::Vector2u screenWH(videoMode.width, videoMode.height);
    sf::Vector2f viewWH(static_cast<float>(screenWH.x), static_cast<float>(screenWH.y));

    camera.player = &player;
    camera.mapWH = levelWH;
    camera.viewWH = viewWH;
    camera.halfViewWH = sf::Vector2f(viewWH.x/2, viewWH.y/2);
    camera.screenWH = screenWH;

    initializeTileMap(levelWH);

    gameLoop(&window);

    deallocateTileMap();

    return 0;
}
 

please compile it:
Quote
g++ -o buggy ./main.cpp -lsfml-graphics -lsfml-window -lsfml-system -std=c++11
and run it:
Quote
./buggy

Can you spot some visual glitches when the red box (i.e. the player) moves? The movement commands are arrows: left/right. Please press left/right for a while, and write back.
An Escape button closes the application.

Here's the video (taken from the smartphone) presenting the glitches I refer to:
https://www.dropbox.com/s/w038trdfqm55gjl/buggy.mp4?dl=0
(beware, it is ~ 30 MB).

Thank you.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: Hapax on January 20, 2015, 05:52:10 pm
Firstly, this is not really "minimal".

Secondly, I executed it and it doesn't seem to have any problems.

There do seem to be weird things happening to the red square when it moves without the camera. This is, however, not a glitch but an optical illusion. I you wish to test this, take a screen shot of the red square near the middle, load it into Photoshop or similar, and move the image. The same seemingly-overlapping dark areas appear there too.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 20, 2015, 05:56:53 pm
Hapax, thank you. I really appreciate your help.
Yes, I know what you're talking about while saying about an optical illusion, yes, it is ok.
But I do see visual problems of another kind related to the edges of yellow/green squares.
It can be seen in the video I supplied.

Probably it is the Nvidia Video Tearing explained here:
http://askubuntu.com/questions/125245/how-do-i-stop-video-tearing-nvidia-prop-driver-non-compositing-window-manager

Btw, what OS are you running on? Can the video driver be the cause of the problem?
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: Hapax on January 20, 2015, 06:13:50 pm
It could be a driver problem; who knows? Make sure you're using the very latest version  :)

Just saw your video. It's a massive tear, isn't it?!
Have you tried using vsync?

p.s. If you use vsync (setVerticalSyncEnabled(true)), remember to stop using setFramerateLimit().
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 20, 2015, 07:05:06 pm
huh, yes, it is related to the Nvidia tearing. it behaves even worse when the application runs in the fullscreen mode.
Hapax,
could you test out that my example works fine with fullscreen mode, i.e.:
int main() {
     sf::VideoMode videoMode = sf::VideoMode::getFullscreenModes().front();

    window.create(videoMode, "test smooth movement", sf::Style::Fullscreen, sf::ContextSettings {});
    ..//
 

I am very curious to compare your results with mine.
Again, thanks for your patience ;)
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: Hapax on January 20, 2015, 07:37:02 pm
Yes, this causes tears when run on my computer. As mentioned earlier, however, it simply requires:
        window.create(videoMode, "test smooth movement", sf::Style::Fullscreen, sf::ContextSettings{});
        window.setVerticalSyncEnabled(true);
        //window.setFramerateLimit(60);
to fix it.

EDIT: It's not perfect, actually; it seems there is a slight fringing where the yellow meets the black but that could be my monitor. Unfortunately, I can't go full-screen on my other monitor yet. Still waiting for SFML's ability to do that (hint hint! ;)). That said, if you're still having identical problems after enabling vertical sync, you should check your drivers to make sure that v-sync can be controlled by applications.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 21, 2015, 06:19:01 am
Tried to enable vertical sync and disable frame limit, but the bug is still here :-/
is that 100% video drivers bug? I am asking because I do not experience that bug in the other OpenGL applications like glxgears for instance (while rotating the gears).
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: Jesper Juhl on January 21, 2015, 10:45:55 pm
Your driver could be configured to not allow applications to control vsync. Make sure your driver allows your app to enable/disable vsync and does not force it on/off.
Ohh and make sure it (the driver) is up-to-date.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: Hapax on January 22, 2015, 02:07:58 am
@Jesper : what I said???

(joke :P)
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 23, 2015, 03:14:49 pm
In nvidia-settings I check/uncheck "VSYNC" but it makes no difference, that's my problem.
Moreover, I tried to explicitly set setVerticalSyncEnabled(true) (using driver's VSYNC on/off), but it is pointless anyway.

a bit more information about my video card, graphics, openGL renderer etc:
Quote
inxi -Gxx

Graphics:  Card: NVIDIA G71 [GeForce 7900 GS] bus-ID: 01:00.0 chip-ID: 10de:0292
           X.Org: 1.15.1 drivers: nvidia (unloaded: fbdev,vesa,nouveau) Resolution: 1680x1050@59.9hz
           GLX Renderer: GeForce 7900 GS/PCIe/SSE2 GLX Version: 2.1.2 NVIDIA 304.125 Direct Rendering: Yes


I am desperate.
Title: AW: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: eXpl0it3r on January 23, 2015, 08:32:42 pm
How many other OpenGL applications which do similar movements have you tested?
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 24, 2015, 07:58:04 pm
no one. ;)
But I don't get what's wrong with my code. if there's a bug, I cannot trace it.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 25, 2015, 10:15:52 am
okay, I *eliminated* all my interpolation for render, and came up with very simple example, which, sadly, doesn't work as supposed. No tiles, just yellow background and the red square. I still see micro-glitches and tearing:

#include <iostream>

#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/System/Clock.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/System/Vector2.hpp>

enum E_MOVE_TYPE {
    LEFT, RIGHT, IDLE
};

struct Entity {
    sf::RectangleShape shape;
    sf::Vector2f pos;
    E_MOVE_TYPE stepX;
    sf::Vector2f vxy;

    void update(float dt) {
        sf::Vector2f movement(0, 0);
        if (stepX == E_MOVE_TYPE::LEFT) {
            movement.x -= vxy.x;
        } else if (stepX == E_MOVE_TYPE::RIGHT) {
            movement.x += vxy.x;
        }
        shape.move(movement*dt);
    }

    void render(sf::RenderWindow *window, sf::RenderStates states) {
        window->draw(shape, states);
    }
};

//GLOBAL VARIABLES
Entity player;

////////
void updateLogic(float dt) {
    player.update(dt);
}

void render(sf::RenderWindow *window) {
    window->clear(sf::Color::Yellow);
    player.render(window, sf::RenderStates::Default);
}

void gameLoop(sf::RenderWindow *window) {

    const sf::Time UPDATE_STEP = sf::seconds(1.0f / 60.0f);
    sf::Time timeSinceLastUpdate = sf::Time::Zero;

    sf::Clock clock;
    while (window->isOpen()) {

        sf::Time dt = clock.restart();
        timeSinceLastUpdate += dt;

        while (timeSinceLastUpdate > UPDATE_STEP) {

            timeSinceLastUpdate -= UPDATE_STEP;

            sf::Event event;
            while (window->pollEvent(event)) {
                switch (event.type) {
                    case sf::Event::KeyPressed:
                        switch (event.key.code) {
                        case sf::Keyboard::Escape:
                            window->close();
                            break;
                        case sf::Keyboard::Left:
                            player.stepX = E_MOVE_TYPE::LEFT;
                            break;
                        case sf::Keyboard::Right:
                            player.stepX = E_MOVE_TYPE::RIGHT;
                            break;
                        break;
                    case sf::Event::KeyReleased:
                        player.stepX = E_MOVE_TYPE::IDLE;
                        break;
                    case sf::Event::Closed:
                        window->close();
                        break;
                    }
                }
            }
            updateLogic(UPDATE_STEP.asSeconds());
        }

        render(window);
        window->display();
    }
}

int main() {

    sf::RenderWindow window;
    window.create(sf::VideoMode(640, 480), "test smooth movement", sf::Style::Close);
    window.setFramerateLimit(60);

    player.pos = sf::Vector2f(10.0, 240.0);
    player.stepX = E_MOVE_TYPE::IDLE;
    player.shape.setSize(sf::Vector2f(40, 40));
    player.shape.setPosition(player.pos);
    player.shape.setFillColor(sf::Color::Red);
    player.vxy = sf::Vector2f(100, 0);

    gameLoop(&window);

    return 0;
}
 

compile it with:
Quote
g++ -o buggy ./main.cpp -lsfml-graphics -lsfml-window -lsfml-system -std=c++11 -Wall
run it:
Quote
./buggy

I see tearing when the red square moves. Can somebody confirm that?
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: Laurent on January 25, 2015, 10:55:58 am
Same if you replace framerate limit with v-sync?
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 25, 2015, 11:05:50 am
yes :-/

btw, I have tried a few OpenGL games to test that they do not suffer from the tearing.
yes, all games I have tried so far run smoothly, including SuperTux (it has an option to use OpenGL renderer), and such giants as WarZone 2100 (it uses OpenGL renderer).

tried switching to FluxBox desktop environment from XFCE4, tested on two computers (namely, PC and notebook, i.e. they have different video cards, although both have Nvidia ones), nothing changes.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: binary1248 on January 25, 2015, 11:25:55 am
Might be related to this (https://github.com/SFML/SFML/issues/727).

The fix is described in that issue and on the linked thread. See if it helps.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 25, 2015, 11:59:41 am
1) changed there the string to "glXSwapIntervalMESA", rebuilt, tested -- nothing changed
I added std::cout to be sure the pointer is valid. in this case it was not (i.e. I haven't seen a line printed in the console).

2) ok, then I changed the string to  "glXSwapIntervalEXT", rebuilt, tested -- my app coredumped and I saw my debug line in the console twice.
GDB reported the following:
Quote
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff23448bd in XQueryExtension () from /usr/lib/x86_64-linux-gnu/libX11.so.6
(gdb) backtrace
#0  0x00007ffff23448bd in XQueryExtension () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#1  0x00007ffff2338be2 in XInitExtension () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#2  0x00007ffff210c8ff in XextAddDisplay () from /usr/lib/x86_64-linux-gnu/libXext.so.6
#3  0x00007ffff66462e3 in ?? () from /usr/lib/nvidia-331/libGL.so.1
#4  0x00007ffff663e299 in glXSwapIntervalEXT () from /usr/lib/nvidia-331/libGL.so.1

3) then I reverted everything back and added std::cout to be sure it gets applied.
and, suddenly, it reports that it is enabled even when I do not explicitly set it in my application!

But the problem is that the movement is yet buggy...

4) binary1248, finally I applied your patch, i.e. checked out your branch, rebuilt SFML, recompiled my test application.
it gives an error:
Quote
X Error of failed request:  BadMatch (invalid parameter attributes)
  Major opcode of failed request:  2 (X_ChangeWindowAttributes)
  Serial number of failed request:  55
  Current serial number in output stream:  57
and terminates. no coredumps, at least ;)
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: binary1248 on January 26, 2015, 03:44:27 am
finally I applied your patch, i.e. checked out your branch, rebuilt SFML, recompiled my test application.
it gives an error:
That branch isn't complete yet (i.e. I know it is broken). I am waiting for the other OpenGL stuff to be finished before I work on this again.

What is the output of glxinfo?
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 26, 2015, 06:38:36 am
good day.
here's the glxinfo output from the first computer (PC):
(click to show/hide)

I'll paste the output from another computer (notebook) later as well.

Updated:
here comes the output from the notebook:
(click to show/hide)
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: binary1248 on January 27, 2015, 03:30:09 am
Well... according to glxinfo you should be able to use glXSwapIntervalEXT (and it crashing is probably the main problem). Can you show us more frames? The backtrace starts inside the GL library, which is too deep to provide us with any useful information.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 27, 2015, 07:52:28 am
I use debug SFML libraries built.
Okay, I use the GDB, executing program step by step:

Quote
234       window.setVerticalSyncEnabled(true);
(gdb) s
sf::Window::setVerticalSyncEnabled (this=0xbfffee40, enabled=true) at /home/varnie/thrash/SFML/src/SFML/Window/Window.cpp:278
278       if (setActive())
(gdb) s
sf::Window::setActive (this=0xbfffee40, active=true) at /home/varnie/thrash/SFML/src/SFML/Window/Window.cpp:320
320       if (m_context)
(gdb) s
322           if (m_context->setActive(active))
(gdb) s
sf::priv::GlContext::setActive (this=0x82371a8, active=true) at /home/varnie/thrash/SFML/src/SFML/Window/GlContext.cpp:216
216       if (active)
(gdb) s
218           if (this != currentContext)
(gdb) s
sf::ThreadLocalPtr<sf::priv::GlContext>::operator sf::priv::GlContext* (this=0xb7f79744 <(anonymous namespace)::currentContext>)
    at /home/varnie/thrash/SFML/include/SFML/System/ThreadLocalPtr.inl:56
56       return static_cast<T*>(getValue());
(gdb) s
sf::ThreadLocal::getValue (this=0xb7f79744 <(anonymous namespace)::currentContext>) at /home/varnie/thrash/SFML/src/SFML/System/ThreadLocal.cpp:64
64       return m_impl->getValue();
(gdb) s
sf::priv::ThreadLocalImpl::getValue (this=0x806c8e8) at /home/varnie/thrash/SFML/src/SFML/System/Unix/ThreadLocalImpl.cpp:59
59       return pthread_getspecific(m_key);
(gdb) s
__GI___pthread_getspecific (key=3) at pthread_getspecific.c:26
26   pthread_getspecific.c: No such file or directory.
(gdb) s
__x86.get_pc_thunk.bx () at ../sysdeps/i386/crti.S:66
66   ../sysdeps/i386/crti.S: No such file or directory.
(gdb) s
__GI___pthread_getspecific (key=3) at pthread_getspecific.c:31
31   pthread_getspecific.c: No such file or directory.
(gdb) s
32   in pthread_getspecific.c
(gdb) s
56   in pthread_getspecific.c
(gdb) s
57   in pthread_getspecific.c
(gdb) s
61   in pthread_getspecific.c
(gdb) s
66   in pthread_getspecific.c
(gdb) s
sf::priv::ThreadLocalImpl::getValue (this=0x806c8e8) at /home/varnie/thrash/SFML/src/SFML/System/Unix/ThreadLocalImpl.cpp:60
60   }
(gdb) s
sf::ThreadLocal::getValue (this=0xb7f79744 <(anonymous namespace)::currentContext>) at /home/varnie/thrash/SFML/src/SFML/System/ThreadLocal.cpp:65
65   }
(gdb) s
sf::ThreadLocalPtr<sf::priv::GlContext>::operator sf::priv::GlContext* (this=0xb7f79744 <(anonymous namespace)::currentContext>)
    at /home/varnie/thrash/SFML/include/SFML/System/ThreadLocalPtr.inl:57
57   }
(gdb) s
sf::priv::GlContext::setActive (this=0x82371a8, active=true) at /home/varnie/thrash/SFML/src/SFML/Window/GlContext.cpp:235
235               return true;
(gdb) s
252   }
(gdb) s
sf::Window::setActive (this=0xbfffee40, active=true) at /home/varnie/thrash/SFML/src/SFML/Window/Window.cpp:324
324               return true;
(gdb) s
336   }
(gdb) s
sf::Window::setVerticalSyncEnabled (this=0xbfffee40, enabled=true) at /home/varnie/thrash/SFML/src/SFML/Window/Window.cpp:279
279           m_context->setVerticalSyncEnabled(enabled);
(gdb) s
sf::priv::GlxContext::setVerticalSyncEnabled (this=0x82371a8, enabled=true) at /home/varnie/thrash/SFML/src/SFML/Window/Unix/GlxContext.cpp:160
160       const GLubyte* name = reinterpret_cast<const GLubyte*>("glXSwapIntervalEXT");
(gdb) s
161       PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = reinterpret_cast<PFNGLXSWAPINTERVALSGIPROC>(glXGetProcAddress(name));
(gdb) s
162       if (glXSwapIntervalSGI)
(gdb) s
163           glXSwapIntervalSGI(enabled ? 1 : 0);
(gdb) s

Program received signal SIGSEGV, Segmentation fault.
0xb5b50f6a in XQueryExtension () from /usr/lib/i386-linux-gnu/libX11.so.6
(gdb) backtrace
#0  0xb5b50f6a in XQueryExtension () from /usr/lib/i386-linux-gnu/libX11.so.6
#1  0xb5b4522e in XInitExtension () from /usr/lib/i386-linux-gnu/libX11.so.6
#2  0xb5b1d6ee in XextAddDisplay () from /usr/lib/i386-linux-gnu/libXext.so.6
#3  0xb7b7e0ff in ?? () from /usr/lib/nvidia-304/libGL.so.1
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) info registers
eax            0xbfffea84   -1073747324
ecx            0xb7e13420   -1209977824
edx            0x1   1
ebx            0xb5c56000   -1245356032
esp            0xbfffea10   0xbfffea10
ebp            0xb7bbfe14   0xb7bbfe14
esi            0x1   1
edi            0xbfffeda8   -1073746520
eip            0xb5b50f6a   0xb5b50f6a <XQueryExtension+26>
eflags         0x10286   [ PF SF IF RF ]
cs             0x73   115
ss             0x7b   123
ds             0x7b   123
es             0x7b   123
fs             0x0   0
gs             0x33   51

After we executed
Quote
glXSwapIntervalSGI(enabled ? 1 : 0);
we have the corrupted stack.

Just a guess, maybe the following is incorrect:
Quote
const GLubyte* name = reinterpret_cast<const GLubyte*>("glXSwapIntervalEXT");
 PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = reinterpret_cast<PFNGLXSWAPINTERVALSGIPROC>

Shouldn't it be
Quote
PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = reinterpret_cast<PFNGLXSWAPINTERVALEXTPROC>

I.e. do all these function pointers have the same signature, maybe in case of glxSwapIntervalEXT it should have the different signature..?
From there: http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/2010-January/063396.html
Quote
The attached patch fixes a crash in MPlayer when using "-vo gl" with recent
NVIDIA drivers.

The function prototypes for glxSwapIntervalSGI and glxSwapIntervalEXT are:

int glXSwapIntervalSGI(int interval);

void glXSwapIntervalEXT(Display *dpy, GLXDrawable drawable, int interval);

However, libvo/gl_common.c assigns either of those functions to the
SwapInterval pointer, and libvo/vo_gl.c calls through that pointer using
glxSwapIntervalSGI's prototype. This effectively passes invalid parameters to
glxSwapIntervalEXT, and causes a segfault.

Note: NVIDIA's 195.* drivers implement both of these functions; previous
drivers implemented only glxSwapIntervalSGI.

This source https://www.opengl.org/registry/specs/EXT/swap_control.txt confirms that that function has a different signature:
    void glXSwapIntervalEXT(Display *dpy,
                            GLXDrawable drawable,
                            int interval);
 
.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: binary1248 on January 27, 2015, 04:14:53 pm
Oh... wait... you didn't change the call to fit the signature? ;D

Yeah... I should have mentioned that. ::)

What happens when you call it with the right arguments? Does the issue resolve itself?
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 27, 2015, 04:39:06 pm
to be honest, I don't understand well how the call should look like (i.e. I am about the other arguments passed to the function).
for example, how can I obtain Display and GLXDrawable from that part of code in SFML?
thank you for clarifications.

Updated: okay, I got it. first test shows that now v-syncs got applied! I'll try my other SFML app too.
Updated: yay, my test SFML app works now!!!  no more tearing and glitches!

if you care, here's the code which did the trick for my nvidia-card:
void GlxContext::setVerticalSyncEnabled(bool enabled)
{
    const GLubyte* name = reinterpret_cast<const GLubyte*>("glXSwapIntervalEXT");
    PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = reinterpret_cast<PFNGLXSWAPINTERVALEXTPROC>(glXGetProcAddress(name));
    if (glXSwapIntervalEXT)
        glXSwapIntervalEXT(m_display, m_window, enabled ? 1 : 0);
}
 

BUT as for notebook, it didn't work. :-/
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: binary1248 on January 28, 2015, 12:53:01 am
Does your notebook have switchable graphics (i.e. IGP + discrete GPU)? Did you try other games on your notebook as well to see if they exhibit tearing? Can you check if any of the glXSwapInterval (EXT/MESA/SGI) functions are found/called by the code?
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 28, 2015, 07:27:27 am
Hi.
I am continuing exploring the obscure depths of video system on my notebook ;)

You're right, I have an integrated video card (intel) and nvidia geforce gt 635m.
I downloaded a standalone openGL app to test whether or not glXSwapIntervalEXT works on the notebook. It gets invoked, but makes no difference. I perform FPS calculation with and without glXSwapIntervalEXT being set, but the results are the same: the FPS remains high, (~1500 FPS or above).
That test OpenGL program works correctly on my PC; I see 60 FPS when that function is set.

I'll test other games and write back.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 28, 2015, 05:51:53 pm
yes, as I guessed, all OpenGL games run smoothly.
speaking about Warzone 2100, it has an option in the game menu to enable/disable vsync. in both cases the game runs without any glitches.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 29, 2015, 02:30:53 pm
if I even don't have
window.setVerticalSyncEnabled(true);
 
in my SFML app, I see in the console that that method gets invoked once, is this intentional?
hmm, yes:
void Window::initialize()
...
setVerticalSyncEnabled(false);
...
 
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: binary1248 on January 29, 2015, 03:03:12 pm
Can you temporarily disable your IGP and try running your SFML application on your notebook? Sometimes the wrong adapter gets selected and many things in SFML go awry because of that.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: grok on January 29, 2015, 09:27:29 pm
I tried really hard to disable IGP, but it led to Nvidia driver (!) refused to load. Weird.
What I did: put i915 (Intel driver) into /etc/modprobe.d/blacklist, rebooted, checked that Intel IGP is not "detected" by the system. So far so good. Funny moment is that now I cannot enable my Nvidia card. nvidia-settings doesn't recognize it, reinstalling Nvidia drivers didn't help.

Then I removed my i915 entriy from the blacklist, installed i915 driver, removed nvidia one, rebooted and voilĂ , - I have stable 59-60 FPS running any SFML apps with/or without vsync enabled in the code. What matters is that there's no more tearing.

Looks like having hybrid graphics has its drawbacks, or maybe it is an Nvidia fault. I still don't get why I couldn't force Nvidia to work with vsync.
Title: Re: Problem with smooth movement in 2d game (scrolling view, render interpolation)
Post by: binary1248 on January 29, 2015, 09:40:20 pm
This is why. (https://www.youtube.com/watch?v=IVpOyKCNZYw)