Opening and managing a sfml window

Playing with the window

Of course, SFML allows you to play with your windows a bit. Basic window operations such as changing the size, position, title or
icon are supported, but unlike dedicated GUI libraries (Qt, wxWidgets), SFML doesn’t provide advanced features. SFML windows are only meant to provide
an environment for OpenGL or SFML drawing.

You can refer to the API documentation for a complete list of ‘s functions.

In case you really need advanced features for your window, you can create one (or even a full GUI) with another library, and embed SFML into it.
To do so, you can use the other constructor, or function, of which takes the OS-specific
handle of an existing window. In this case, SFML will create a drawing context inside the given window and catch all its events without interfering with
the parent window management.

If you just want an additional, very specific feature, you can also do it the other way round: create an SFML window and get its OS-specific handle
to implement things that SFML itself doesn’t support.

Integrating SFML with other libraries requires some work and won’t be described here, but you can refer to the dedicated tutorials, examples or
forum posts.

Opening a window

Windows in SFML are defined by the class. A window can be created and opened directly upon construction:

The first argument, the video mode, defines the size of the window (the inner size, without the title bar and borders). Here, we create
a window with a size of 800×600 pixels.
The class has some interesting static functions to get the desktop resolution, or the list of valid video modes for
fullscreen mode. Don’t hesitate to have a look at its documentation.

The second argument is simply the title of the window.

This constructor accepts a third optional argument: a style, which allows you to choose which decorations and features you want. You can use any
combination of the following styles:

No decoration at all (useful for splash screens, for example); this style cannot be combined with others
The window has a titlebar
The window can be resized and has a maximize button
The window has a close button
The window is shown in fullscreen mode; this style cannot be combined with others, and requires a valid video mode
The default style, which is a shortcut for

There’s also a fourth optional argument, which defines OpenGL specific options which are explained in the
dedicated OpenGL tutorial.

If you want to create the window after the construction of the instance, or re-create it with a different
video mode or title, you can use the function instead. It takes the exact same arguments as the constructor.

Built-in shape types

To draw rectangles, you can use the class. It has a single attribute: The size of the rectangle.

Circles

Circles are represented by the class. It has two attributes: The radius and the number of sides. The number of sides is an optional
attribute, it allows you to adjust the «quality» of the circle: Circles have to be approximated by polygons with many sides (the graphics card is unable to draw a perfect
circle
directly), and this attribute defines how many sides your circle approximation will have. If you draw small circles, you’ll probably only need a few sides. If you draw big
circles, or zoom on regular circles, you’ll most likely need more sides.

Regular polygons

There’s no dedicated class for regular polygons, in fact you can represent a regular polygon with any number of sides using the class:
Since circles are approximated by polygons with many sides, you just have to play with the number of sides to get the desired polygons. A with 3 points is a triangle, with 4 points it’s a square, etc.

Convex shapes

The class is the ultimate shape class: It allows you to define any convex shape. SFML is unable to draw
concave shapes. If you need to draw a concave shape, you’ll have to split it into multiple convex polygons.

To construct a convex shape, you must first set the number of points it should have and then define the points.

The order in which you define the points is very important. They must all be defined either in clockwise or counter-clockwise order. If you
define them in an inconsistent order, the shape will be constructed incorrectly.

Lines

There’s no shape class for lines. The reason is simple: If your line has a thickness, it is a rectangle. If it doesn’t, it can be drawn with a line primitive.

Line with thickness:

Line without thickness:

To learn more about vertices and primitives, you can read the tutorial on
vertex arrays.

Non-blocking sockets

All sockets are blocking by default, but you can change this behaviour at any time with the function.

Once a socket is set as non-blocking, all of its functions always return immediately. For example, will return with status
if there’s no data available. Or, will return immediately, with the same status, if there’s no pending connection.

Non-blocking sockets are the easiest solution if you already have a main loop that runs at a constant rate. You can simply check if something happened on your sockets
in every iteration, without having to block program execution.

When using in non-blocking mode, calls to are not guaranteed to actually send all the data you pass to it, whether it be
as a or as raw data. Starting from SFML 2.3, when sending raw data over a non-blocking , always make sure to use the
overload which returns the number of bytes actually sent in the reference
parameter after the function returns. Regardless of whether you send s or raw data, if only a part of the data was sent in the call, the return
status will be to indicate a partial send. If is returned, you must make sure to handle the partial
send properly or else data corruption will occur. When sending raw data, you must reattempt sending the raw data at the byte offset where the previous
call stopped. When sending s, the byte offset is saved within the itself. In this case, you must make sure to keep
attempting to send the exact same unmodified object over and over until a status other than is returned.
Constructing a new object and filling it with the same data will not work, it must be the same object that was previously sent.

Using a UDP socket

UDP sockets are connectionless, so they are the easiest ones to use. No connection is needed,
all you have to do is sending and receiving data. The only step required is to bind the socket to a port before
receiving data.

SFML sockets allow sending raw data, defined by a pointer to a byte array and its size :

Here, we send our byte array (containing «Hi guys !») to the computer which IP address is 192.168.0.2,
on port 4567. The second parameter is a , so you could as well
use a network name, a broadcast address or whatever type of address.
If you don’t want to use a specific port, you can just take any free port number between 1024 and
65535 (ports less than 1024 are reserved). And of course, make sure that your firewall is not
blocking this port !

The function, as well as all other functions that can block,
returns a socket status (see ) which can be :

  • : the operation has been completed with success
  • : in non-blocking mode only, returned when the socket is not yet ready to complete the task
  • : the socket has been disconnected
  • : an unexpected error happened

Receiving data is exactly the same, except you first need to bind the socket to a port before
receiving data from this port.

Then you can receive a byte array, its size, and the address / port of the sender.

Please note that is blocking, meaning that it won’t return
until it has received something if the socket is in blocking mode (which is the default).

When you don’t need the socket anymore, you have to close it (the destructor won’t do it for you !) :

Create your first SFML program

We provide two templates for Xcode. SFML CLT generates a project for a classic terminal program whereas SFML App creates a project for an application
bundle. We will use the latter here but they both work similarly.

First select File > New Project... then choose SFML in the left column and double-click on SFML App.

Now you can fill in the required fields as shown in the following screenshot. When you are done click next.

Your new project is now set to create an
.

Now that your project is ready, let’s see what is inside:

As you can see, there are already a few files in the project. There are three important kinds:

  1. Header & source files: the project comes with a basic example in main.cpp and the helper function in
    ResourcePath.hpp and ResourcePath.mm. The purpose of this function, as illustrated in the provided example, is to provide a convenient way to access
    the Resources folder of your application bundle.
    Please note that this function only works on macOS. If you are planning to make your application work on other operating systems, you should implement your own version of this
    function on the operating systems in question.
  2. Resource files: the resources of the basic example are put in this folder and are automatically copied to your application bundle when you compile it.
    To add new resources to your project, simply drag and drop them into this folder and make sure that they are a member of your application target; i.e. the box under
    Target Membership in the utility area (cmd+alt+1) should be checked.
  3. Products: your application. Simply press the Run button to test it.

The other files in the project are not very relevant for us here. Note that the SFML dependencies of your project are added to your application bundle
in a similar in which the resources are added. This is done so that your application will run out of the box on another Mac without any prior installation of SFML or its dependencies.

Common shape properties

Transformation (position, rotation, scale)

These properties are common to all the SFML graphical classes, so they are explained in a separate tutorial:
Transforming entities.

One of the basic properties of a shape is its color. You can change with the function.

Outline

Shapes can have an outline. You can set the thickness and color of the outline with the and functions.

By default, the outline is extruded outwards from the shape (e.g. if you have a circle with a radius of 10 and an outline thickness of 5, the total radius of the circle will be 15).
You can make it extrude towards the center of the shape instead, by setting a negative thickness.

To disable the outline, set its thickness to 0. If you only want the outline, you can set the fill color to .

Texture

Shapes can also be textured, just like sprites. To specify a part of the texture to be mapped to the shape, you must use the function.
It takes the texture rectangle to map to the bounding rectangle of the shape. This method doesn’t offer maximum flexibility, but it is much easier to use than
individually setting the texture coordinates of each point of the shape.

Note that the outline is not textured.
It is important to know that the texture is modulated (multiplied) with the shape’s fill color. If its fill color is sf::Color::White, the texture will appear unmodified.
To disable texturing, call .

Connecting a TCP socket

As you can guess, this part is specific to TCP sockets. There are two sides to a connection: the one that waits for the incoming connection (let’s call it the server),
and the one that triggers it (let’s call it the client).

On client side, things are simple: the user just needs to have a and call its function to start the connection attempt.

The first argument is the address of the host to connect to. It is an , which can represent any valid address: a URL, an IP address, or a
network host name. See its documentation for more details.

The second argument is the port to connect to on the remote machine. The connection will succeed only if the server is accepting connections on that port.

There’s an optional third argument, a time out value. If set, and the connection attempt doesn’t succeed before the time out is over, the function returns an error. If not specified,
the default operating system time out is used.

Once connected, you can retrieve the address and port of the remote computer if needed, with the and
functions.

All functions of socket classes are blocking by default. This means that your program (more specifically the thread that contains the function call) will be stuck until the
operation is complete. This is important because some functions may take very long: For example, trying to connect to an unreachable host will only return after a few seconds,
receiving will wait until there’s data available, etc.
You can change this behavior and make all functions non-blocking by using the function of the socket. See the next chapters for more details.

On the server side, a few more things have to be done. Multiple sockets are required: One that listens for incoming connections, and one for each connected client.

To listen for connections, you must use the special class. Its only role is to wait for incoming connection attempts on a given port, it can’t
send or receive data.

The function blocks until a connection attempt arrives (unless the socket is configured as non-blocking). When it happens, it initializes the given socket
and returns. The socket can now be used to communicate with the new client, and the listener can go back to waiting for another connection attempt.

After a successful call to (on client side) and (on server side), the communication is established and both sockets are ready
to exchange data.

Non-blocking sockets

All sockets are blocking by default, but you can change this behaviour at any time with the function.

Once a socket is set as non-blocking, all of its functions always return immediately. For example, will return with status
if there’s no data available. Or, will return immediately, with the same status, if there’s no pending connection.

Non-blocking sockets are the easiest solution if you already have a main loop that runs at a constant rate. You can simply check if something happened on your sockets
in every iteration, without having to block program execution.

When using in non-blocking mode, calls to are not guaranteed to actually send all the data you pass to it, whether it be
as a or as raw data. Starting from SFML 2.3, when sending raw data over a non-blocking , always make sure to use the
overload which returns the number of bytes actually sent in the reference
parameter after the function returns. Regardless of whether you send s or raw data, if only a part of the data was sent in the call, the return
status will be to indicate a partial send. If is returned, you must make sure to handle the partial
send properly or else data corruption will occur. When sending raw data, you must reattempt sending the raw data at the byte offset where the previous
call stopped. When sending s, the byte offset is saved within the itself. In this case, you must make sure to keep
attempting to send the exact same unmodified object over and over until a status other than is returned.
Constructing a new object and filling it with the same data will not work, it must be the same object that was previously sent.

Installing SFML

First, you must download the SFML SDK from the download page.

There are multiple variants of GCC for Windows, which are incompatible with each other (different exception management,
threading model, etc.). Make sure you select the package which corresponds to the version that you use. If you are unsure, check which of
the libgcc_s_sjlj-1.dll or libgcc_s_dw2-1.dll files is present in your MinGW/bin folder. If MinGW was installed along with Code::Blocks,
you probably have an SJLJ version.

If you feel like your version of GCC can’t work with the precompiled SFML libraries, don’t hesitate to
build SFML yourself, it’s not complicated.

You can then unpack the SFML archive wherever you like. Copying headers and libraries to your installation of MinGW is not recommended, it’s better
to keep libraries in their own separate location, especially if you intend to use several versions of the same library, or several compilers.

Introduction

Admittedly, the title of this tutorial is a bit misleading. You will not compile SFML with CMake, because CMake is not
a compiler. So… what is CMake?

CMake is an open-source meta build system. Instead of building SFML, it builds what builds SFML: Visual Studio solutions,
Code::Blocks projects, Linux makefiles, XCode projects, etc. In fact it can generate the makefiles or projects for any operating system and compiler of
your choice. It is similar to autoconf/automake or premake for those who are already familiar with these tools.

CMake is used by many projects including well-known ones such as Blender, Boost, KDE, and Ogre. You can read more about CMake on its
official website or in its
Wikipedia article.

As you might expect, this tutorial is divided into two main sections: Generating the build configuration with CMake, and building SFML with
your toolchain using that build configuration.

Non-blocking sockets

All sockets are blocking by default, but you can change this behaviour at any time with the function.

Once a socket is set as non-blocking, all of its functions always return immediately. For example, will return with status
if there’s no data available. Or, will return immediately, with the same status, if there’s no pending connection.

Non-blocking sockets are the easiest solution if you already have a main loop that runs at a constant rate. You can simply check if something happened on your sockets
in every iteration, without having to block program execution.

When using in non-blocking mode, calls to are not guaranteed to actually send all the data you pass to it, whether it be
as a or as raw data. Starting from SFML 2.3, when sending raw data over a non-blocking , always make sure to use the
overload which returns the number of bytes actually sent in the reference
parameter after the function returns. Regardless of whether you send s or raw data, if only a part of the data was sent in the call, the return
status will be to indicate a partial send. If is returned, you must make sure to handle the partial
send properly or else data corruption will occur. When sending raw data, you must reattempt sending the raw data at the byte offset where the previous
call stopped. When sending s, the byte offset is saved within the itself. In this case, you must make sure to keep
attempting to send the exact same unmodified object over and over until a status other than is returned.
Constructing a new object and filling it with the same data will not work, it must be the same object that was previously sent.

The TextEntered event

The event is triggered when a character is typed. This must not be confused with the
event: interprets the user input and produces the appropriate printable character. For example, pressing ‘^’ then ‘e’
on a French keyboard will produce two events, but a single event containing the ‘ê’ character.
It works with all the input methods provided by the operating system, even the most specific or complex ones.

This event is typically used to catch user input in a text field.

The member associated with this event is , it contains the Unicode value of the entered character. You can either put it
directly in a , or cast it to a after making sure that it is in the ASCII range (0 — 127).

Note that, since they are part of the Unicode standard, some non-printable characters such as backspace are generated by this event.
In most cases you’ll need to filter them out.

Many programmers use the event to get user input, and start to implement crazy algorithms that try to interpret all
the possible key combinations to produce correct characters. Don’t do that!

Detailed Description

Window that serves as a target for OpenGL rendering.

sf::Window is the main class of the Window module.

It defines an OS window that is able to receive an OpenGL rendering.

A sf::Window can create its own new window, or be embedded into an already existing control using the create(handle) function. This can be useful for embedding an OpenGL rendering area into a view which is part of a bigger GUI with existing windows, controls, etc. It can also serve as embedding an OpenGL rendering area into a window created by another (probably richer) GUI library like Qt or wxWidgets.

The sf::Window class provides a simple interface for manipulating the window: move, resize, show/hide, control mouse cursor, etc. It also provides event handling through its and functions.

Note that OpenGL experts can pass their own parameters (antialiasing level, bits for the depth and stencil buffers, etc.) to the OpenGL context attached to the window, with the sf::ContextSettings structure which is passed as an optional argument when creating the window.

On dual-graphics systems consisting of a low-power integrated GPU and a powerful discrete GPU, the driver picks which GPU will run an SFML application. In order to inform the driver that an SFML application can benefit from being run on the more powerful discrete GPU, can be placed in a source file that is compiled and linked into the final application. The macro should be placed outside of any scopes in the global namespace.

Usage example:

sf::Window window(sf::VideoMode(800, 600), «SFML window»);

window.(60);

while (window.())
{

sf::Event event;
while (window.(event))
{

if (event. == )
window.();
}

window.();

window.();
}

Definition at line of file Window/Window.hpp.

Sending and receiving data

Sending and receiving data is done in the same way for both types of sockets. The only difference is that UDP has two extra arguments: the address and port of the sender/recipient.
There are two different functions for each operation: the low-level one, that sends/receives a raw array of bytes, and the higher-level one, which uses the
class. See the tutorial on packets for more details about this
class. In this tutorial, we’ll only explain the low-level functions.

To send data, you must call the function with a pointer to the data that you want to send, and the number of bytes to send.

The functions take a pointer, so you can pass the address of anything. However, it is generally a bad idea to send something other than
an array of bytes because native types with a size larger than 1 byte are not guaranteed to be the same on every machine: Types such as int or long may have a different size,
and/or a different endianness. Therefore, such types cannot be exchanged reliably across different systems. This problem is explained (and solved) in the
tutorial on packets.

With UDP you can broadcast a message to an entire sub-network in a single call: to do so you can use the special address .

There’s another thing to keep in mind with UDP: Since data is sent in datagrams and the size of these datagrams has a limit, you are not allowed to exceed it.
Every call to must send less that bytes — which is a little less than 2^16 (65536) bytes.

To receive data, you must call the function:

It is important to keep in mind that if the socket is in blocking mode, will wait until something is received, blocking the thread that called it
(and thus possibly the whole program).

The first two arguments specify the buffer to which the received bytes are to be copied, along with its maximum size. The third argument is a variable that will contain the actual
number of bytes received after the function returns.
With UDP sockets, the last two arguments will contain the address and port of the sender after the function returns. They can be used later if you want to send a response.

These functions are low-level, and you should use them only if you have a very good reason to do so. A more robust and flexible approach involves using
packets.

TCP vs UDP

It is important to know what TCP and UDP sockets can do, and what they can’t do, so that you can choose the best socket type according to the requirements of your
application.

The main difference is that TCP sockets are connection-based. You can’t send or receive anything until you are connected to another TCP socket on the remote machine.
Once connected, a TCP socket can only send and receive to/from the remote machine. This means that you’ll need one TCP socket for each client in your application.
UDP is not connection-based, you can send and receive to/from anyone at any time with the same socket.

The second difference is that TCP is reliable unlike UDP. It ensures that what you send is always received, without corruption and in the same order. UDP performs fewer
checks, and doesn’t provide any reliability: what you send might be received multiple times (duplication), or in a different order, or be lost and never reach the remote computer.
However, UDP does guarantee that data which is received is always valid (not corrupted).
UDP may seem scary, but keep in mind that almost all the time, data arrives correctly and in the right order.

The third difference is a direct consequence of the second one: UDP is faster and more lightweight than TCP because it has fewer requirements, thus less overhead.

The last difference is about the way data is transported. TCP is a stream protocol: there’s no message boundary, if you send «Hello» and then «SFML», the remote
machine might receive «HelloSFML», «Hel» + «loSFML», or even «He» + «loS» + «FML».
UDP is a datagram protocol. Datagrams are packets that can’t be mixed with each other. If you receive a datagram with UDP, it is guaranteed to be exactly
the same as it was sent.

Oh, and one last thing: since UDP is not connection-based, it allows broadcasting messages to multiple recipients, or even to an entire network. The one-to-one communication
of TCP sockets doesn’t allow that.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector