Graphics Window

Learn how to create and use the SFML graphics/render window

Code Repository

SFML Graphics and the Render Window

One of the reasons SFML is very simple to use is its Graphics module. The module allows to easily load images and fonts and interact with sprites, texts and shapes very intuitively. Before you can take advantage of the SFML Graphics module you have to create a Window. There are two ways for creating a window with SFML.

  • With the class sf::Window
  • With the class sf::RenderWindow

The only way to take advantage of the SFML Graphics module is to create a window with the class sf::RenderWindow. sf::RenderWindow extends the class sf::Window and adds features that make the manipulation of graphics (shapes, sprites, texts) very easy. The code below shows how to create a window and display a green circle with the SFML Graphics module. You can recreate this code by following the steps below.

////////////////////////////////////////////////////////////
// Nero Game Engine - SFML Tutorials
////////////////////////////////////////////////////////////
#include <SFML/Graphics.hpp>
int main()
{
    //Create Graphics Window
        //window parameters
    sf::Vector2u    window_resolution(1080, 720);
    std::string     window_title = "Graphics Window";
        //create the window
    sf::RenderWindow renderWindow(sf::VideoMode(window_resolution.x, window_resolution.y), window_title);
    //Initialize your game here
        //let's create a simple circle and draw it later
    sf::CircleShape circle;
    circle.setRadius(50.f);
    circle.setOrigin(50.f, 50.f);
    circle.setFillColor(sf::Color::Green);
    circle.setPosition(window_resolution.x/2.f, window_resolution.y/2.f); //center of the screen
    //Game loop
    while (renderWindow.isOpen())
    {
        //handle input events
        //1- Create an empty Event. (Message = "")
        sf::Event event;
        //2- Catch and store the last event inside our empty event object (Message = "something")
        while (renderWindow.pollEvent(event))
        {
            //3- if (Message = The close button has been clicked on) close the window
            if (event.type == sf::Event::Closed)
                renderWindow.close();
        }

        //update your game here
            //we have nothing to update, so it's empty

        //clear the screen with a black color
        renderWindow.clear(sf::Color::Black);
            //draw your game here (it happens in the background, the drawing won't be visible yet)
                //let's draw our circle
            renderWindow.draw(circle);
        //display your screen (now everything becomes visible)
        renderWindow.display();
    }
    return 0;
}

Step 1 - Includes and Main

Using the Engine SDK, create an empty project or a console project, then replace the code inside main.cpp with the code below. To use the SFML Graphics module you have to insert its header SFML/Graphics.hpp.

//Include the SFML Graphics Module header
#include <SFML/Graphics.hpp>
//Create an empty main function
int main()
{
    //Our code will be here
    return 0;
}

Step 2 - Create a Render Window

The SFML Render Window needs three parameters :

  • The window width
  • The window height
  • The window title

The code below combines the window width and height into a single parameter called window resolution. If you place this code inside the main function and compile it, you will see the window appear and then disappear immediately. This is because our program reaches the last line of code “return 0” and exit. To maintain the window visible we need a way to say “stay visible until I close you myself“, let’s see how to do that in the next sections.

//Create Graphics Window
   //window parameters
sf::Vector2u    window_resolution(1080, 720);
std::string     window_title = "Graphics Window";
  //create the window
sf::RenderWindow renderWindow(sf::VideoMode(window_resolution.x, window_resolution.y), window_title);

Step 3 - Maintain the Render Window visible

The way we maintain the window visible is simply by creating an Infinite Loop. The Render Window method isOpen() will always return True until we call its other method close(). By using the method isOpen() and a simple While Loop we can force the window to stay visible. If you compile the code now, the window will be visible but you will observe a little issue : you won’t be able to close the window by clicking on the close/cross button on the top-right of the window.

while (renderWindow.isOpen())
{
    //An infinite loop than force the window to stay visible forever
}

Step 4 - Close the Render Window using a Close Event

Let’s learn how to get the window closed when you press the close/cross button on the top-right of the window. For that, we’ll use an SFML feature called Event. Without entering into the details of Events, here is how it works. When you click on the close button on the top-right of the window, you generate a message “The close button has been clicked on“. Now we need to “catch” that message and respond to it. In SFML this message is called an Event and the way you “catch” it, is by using the Render Window method pollEvent(event) where “event” is an empty sf::Event object used to store the caught event.

while (renderWindow.isOpen())
{
    //An infinite loop than force the window to stay visible forever
    //1- Create an empty Event object, it contains no message(Message = "")
    sf::Event event;
    //2- Catch and store the last event inside our empty event object with the method pollEvent
    //Now the event object contains something, but we don't know what (Message = "something")
    while (renderWindow.pollEvent(event))
    {
       //3- Check the content of the event to see if it is a Close Event
      // if (Message = The close button has been clicked on) close the window
       if (event.type == sf::Event::Closed)
          renderWindow.close();
    }
}

Step 5 - Create a Circle

The SFML Graphics module offers many classes to create simple shapes like Circle, Triangle, Rectangle, and Polygon in general. In the code below we use the class sf::CircleShape to create a circle, then we set its radius at 50.

//Initialize your game here
   //let's create a simple circle and draw it later
sf::CircleShape circle;
circle.setRadius(50.f);
circle.setOrigin(50.f, 50.f);
circle.setFillColor(sf::Color::Green);
circle.setPosition(window_resolution.x/2.f, window_resolution.y/2.f); //center of the screen
while (renderWindow.isOpen())
{
    //An infinite loop than force the window to stay visible forever
    // Catch close Event here (see previous section)
}

By default SFML considers the “origin” of objects (shapes, sprites, text ) to be on the top-left corner (see image below). It feels more intuitive to have the “origin” at the center, so we use the method setOrigin(x, y) to position the origin at the center. Our circle has a radius of 50, so the blue box surrounding it measures 100 on each side, and its middle is simply x = 100/2 = 50 and y = 100/2, so the center is at (50, 50).

You may have already noticed it, SFML y-axis is directed downward. If you ever took a Math class you may be used to have the y-axis directed upward. It is a little bit confusing at the beginning but you will get used to it.

  • x-axis : left to right, positive when moving right and negative when moving left
  • y-axis : up to down, positive when moving down and negative when moving up

Step 6 - Draw our Circle

Now let’s draw our circle inside the Infinite Loop. We take three steps to draw our circle.

  • Step 1 : clear the screen and make everything black
  • Step 2 : draw our circle on the black screen
  • Step 3 : show the result to the viewer (you)
while (renderWindow.isOpen())
{
    //An infinite loop than force the window to stay visible forever
    
    // Catch close Event here (see previous section)
    //clear the screen with a black color
    renderWindow.clear(sf::Color::Black);
       //draw your game here (it happens in the background, the drawing want be visible yet)
       //let's draw our circle
       renderWindow.draw(circle);
    //display your screen (now everything becomes visible)
    renderWindow.display();
}

The reason the circle is not visible when the Render Window method draw() is called, is because SFML draws the circle on a background screen that is not visible until the method display() is called. This technique is called Double Buffering. As you can see in the image below Step 1 and 2 happen in the background then Step 3 shows the result. The two screens continue to swap infinitely at each frame until the window gets closed.