Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Error taking screenshot in the first frame  (Read 5057 times)

0 Members and 1 Guest are viewing this topic.

Ganado

  • Newbie
  • *
  • Posts: 34
  • Moo, I say.
    • View Profile
    • FOnline Engine, check it out.
Error taking screenshot in the first frame
« on: January 20, 2015, 02:24:35 pm »
Could someone kindly tell me why this doesn't work, and if it is considered a bug or not?

The following code does not correctly take a screenshot, the PNG file rendered is blank with RGBA (0, 0, 0, 0).
I have the following code:
#include <SFML/Graphics.hpp>
const int ScreenWidth  = 3000/4;
const int ScreenHeight = 2000/4;

int main()
{
    sf::RenderWindow window(sf::VideoMode(ScreenWidth, ScreenHeight), "SFML Animation"/*, sf::Style::None*/);

    sf::RectangleShape rect(sf::Vector2f(100, 100));
    rect.setPosition(sf::Vector2f(100, 100));

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

        window.clear(sf::Color::Blue);
        window.draw(rect);
        window.display();

        //static int i = 0;
        //if (i++ > 10)
        //{
            sf::Image screenshot = window.capture();
            screenshot.saveToFile("test_big000.png");
            return 0;
        //}

    }
}

If I uncomment the last lines to be the following, to allow more frames to be processed before a screenshot, a correct screenshot is  made:

        static int i = 0;
        if (i++ > 10)  // just to make it have to process the loop a few times
        {
            sf::Image screenshot = window.capture();
            screenshot.saveToFile("test_big000.png");
            return 0;
        }
 

Short version:
Why does the capture() function not work on the first frame of the program?
Is this intended behavior? Couldn't find anything with search to verify this claim.

Also note that the screenshot.saveToFile() is returning true.
I'm on Windows 7, if that matters, using SFML 2.2 compiled from github about a week ago.
« Last Edit: January 20, 2015, 02:29:09 pm by Ganado »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Error taking screenshot in the first frame
« Reply #1 on: January 20, 2015, 02:49:51 pm »
I tested this for you. I found similar - but not equal - results. On the first cycle, it saves a pure blue screenshot (for me).
I confirmed that it has nothing to do with it forcing the window closed so soon afterwards by changing the screenshot code to:
                static bool done = false;
                if (!done)
                {
                        sf::Image screenshot = window.capture();
                        screenshot.saveToFile("G:/Resource Pool/temp/test_big000.png");
                        done = true;
                }
which keeps the window open after taking the screenshot. The screenshot (again, for me) is blue only.

I would suspect that this is closely related to the fact that the window isn't actually drawn instantly so the screenshot is capturing the image before the OS has actually finished displaying the window.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Error taking screenshot in the first frame
« Reply #2 on: January 20, 2015, 02:52:04 pm »
The explanation is simple: double-buffering. After the first frame, only one of the two buffers contains meaningful pixel data, and since you take the screenshot after the call to display(), the buffers have been flipped and you get the contents of the second buffer, which is still empty.
Laurent Gomila - SFML developer

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Error taking screenshot in the first frame
« Reply #3 on: January 20, 2015, 03:03:00 pm »
@Laurent, that sort of makes sense. I would've thought that it would have switched to be displaying the most recent render though. Wouldn't this mean that the frame is also one behind? Also, more confusingly, why did mine capture just blue?
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Ganado

  • Newbie
  • *
  • Posts: 34
  • Moo, I say.
    • View Profile
    • FOnline Engine, check it out.
Re: Error taking screenshot in the first frame
« Reply #4 on: January 20, 2015, 03:11:55 pm »
Thanks for the replies it does make sense, although I had the same thought, does that mean it's a frame behind? It's no big deal for my purposes though.

Edit: As a side note, I'm happy to see that the SFML method of taking a screenshot still seems to work just fine when the screen is bigger than my actual monitor (Just took a 3000x2000 screen and it seems to draw everything correctly)
« Last Edit: January 20, 2015, 03:22:02 pm by Ganado »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Error taking screenshot in the first frame
« Reply #5 on: January 20, 2015, 03:59:14 pm »
I would've thought that it would have switched to be displaying the most recent render though. Wouldn't this mean that the frame is also one behind?
It depends on how you define "most recent". It swaps in the most recent buffer you drew to, so yes in that respect it is the "most recent" but when it is displayed on your screen, you are drawing to a "newer" buffer which will only be displayed after the next swap, so that is the "most recent" buffer that you operate on.

Also, more confusingly, why did mine capture just blue?
It is up to the implementation how it initializes framebuffer memory (SFML doesn't explicitly clear/initialize it for you). Judging by your seeing blue, I'm guessing your driver is "being smart" and perhaps initializing the uninitialized frontbuffer memory when clearing the backbuffer the first time?

Thanks for the replies it does make sense, although I had the same thought, does that mean it's a frame behind? It's no big deal for my purposes though.
See what I wrote above. If you want to capture the "current frame" i.e. the one you most recently drew to, simply call .capture() before calling .display(). SFML makes use of glReadPixels() to capture the screen from the backbuffer, which means that your screenshot is in fact "more fresh" than what you see on your screen if you do it this way.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Error taking screenshot in the first frame
« Reply #6 on: January 20, 2015, 05:17:14 pm »
Thanks for the info, binary. I think I understand a little better. Capture actually captures the currently drawn to "display" and when you call display() for the first time, it swaps it with the never drawn to version and then was trying to capture that.

Just to confirm, if you move the window.display() to after the capture, it works fine.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*