3

Here is a MWE

#include <SFML/Graphics.hpp>


#include <string>
#include <iostream>


int main(int argc, char *argv)
{
    sf::RenderWindow window(sf::VideoMode(200, 200), "Title");

    std::string image_filename;
    image_filename = "image.png";

    sf::Image image;
    if(!image.loadFromFile(image_filename))
    {
        std::cout << "Error: Could not load file " << image_filename << std::endl;
    }

    sf::Texture texture;
    texture.loadFromImage(image);

    sf::Sprite sprite;
    sprite.setTexture(texture);

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        window.clear();
        window.draw(sprite);
        window.display();
    }

    return 0;
}

When starting the application, the window looks like this:

SFML Application with Sprite

After resizing the window, the window looks like this:

SFML Application with Sprite Resize

The global and local bounds of the sprite are the same before and after re-sizing.

The behaviour (as seen in the screenshot) is not what I would expect the default behaviour to be.

  • The number of pixels (width and height) of the window has changed.
  • The same region of the image/texture/sprite is drawn to the window.
  • An interpolation algorithm of some kind has been applied to scale the initial window width and height to the resized window width and height.

Maybe that was already really obvious. This behaviour makes sense when designing something like a game**, but it doesn't make sense for the application I am intending to implement.

** (because the background will "scale" as the window is resized, whereas the rendering resolution would be fixed in advance, likely by a config file)

Before attempting to change the behaviour I want to understand why the behaviour is like this.

Presumably opening a RenderWindow with some initial default resolution (width x height) starts some kind of rendering instance on the GPU with that width and height. Resizing the window on the other hand presumably changes that width and height of the window in the "window system" (window manager, regardless of which OS it is running on) but does not update or change the corresponding width and height on the GPU rendering instance.

Or at least this is my best guess as to what happens.

Is there a way to change this behaviour? Perhaps using something like a SFML RenderWindow is fundamentally the wrong approach to use?

Note: I checked and the "scale" of the sprite does not change during a resize operation. So my assumption would be that the initial window size fixes the resolution of the array of pixels to be rendered and then this is upscaled/downscaled to fit the size of the actual window when drawing pixel data into the display pixel buffer using some kind of interpolation algorithm.

1 Answer 1

2

You can add the following event listener to the events loop:

if(event.type == sf::Event::Resized)
{
    sf::FloatRect view(0, 0, event.size.width, event.size.height);
    window.setView(sf::View(view));
}

This will update the render area to the dimensions of the window every time the window is resized rather than scaling the render area to fit the window.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the suggestion, this seems like it is along the right lines. However at the moment adding just this code in causes some visual artifacts, such as the image (sprite) jumping around as the window is resized. Do I need to add something like a frame rate limit or vsync?
Its possible you are having a syncing issue. If so adding window.setVerticalSyncEnabled(true) after you create the window should solve it in most cases. This function will do nothing if v-syncing has been disabled in the graphics card settings though, in which case you'd need to limit frame rate through window.setFramerateLimit(60) after creating the window.
It doesn't make a difference unfortunatly. I tried first with setVerticalSyncEnabled and then with both that and setFramerateLimit(60) and the behaviour was the same.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.