Using sockets
Содержание:
- Building SFML
- Custom packets
- Установка библиотеки SFML
- Non-blocking sockets
- Packets
- ◆ openFromMemory()
- Header Files
- Common shape properties
- Managing multiple OpenGL windows
- Including and linking OpenGL to your application
- Drawing from threads
- Introduction
- Installing SFML
- ◆ setAttenuation()
- Create your first SFML program
- Opening a window
- ◆ create() [1/2]
- The drawing window
- Detailed Description
Building SFML
Let’s begin this section with some good news: you won’t have to go through the configuration step any more, even if you update your working copy of
SFML. CMake is smart: It adds a custom step to the generated makefiles/projects, that automatically regenerates the build files whenever
something changes.
You’re now ready to build SFML. Of course, how to do it depends on what makefiles/projects you’ve generated. If you created
a project/solution/workspace, open it with your IDE and build SFML like you would any other project. We won’t go into the details here,
there are simply too many different IDEs and we have to assume that you know how to use yours well enough to perform this simple task on your own.
If you generated a makefile, open a command shell and execute the make command corresponding to your environment. For example, run «nmake» if
you generated an NMake (Visual Studio) makefile, «mingw32-make» if you generated a MinGW (GCC) makefile, or simply «make» if you generated a Linux
makefile.
Note: On Windows, the make program (nmake or mingw32-make) may not be accessible. If this is the case, don’t forget to add its location to your PATH
environment variable. See the explanations at the beginning of the «Configuring your SFML build» section for more details.
By default, building the project will build everything (all the SFML libraries, as well as all the examples if you enabled the SFML_BUILD_EXAMPLES option).
If you just want to build a specific SFML library or example, you can select a different target. You can also choose to clean or install the built
files, with the corresponding targets.
Here are all the targets that are available, depending on the configure options that you chose:
Target | Meaning |
---|---|
This is the default target, it is used if no target is explicitly specified. It builds all the targets that produce a binary (SFML libraries and examples). |
|
Builds the corresponding SFML library. The «sfml-main» target is available only when building for Windows. | |
Builds the corresponding SFML example. These targets are available only if the option is enabled. Note that some of the targets are available only on certain operating systems («cocoa» is available on Mac OS X, «win32» on Windows, «X11» on Linux, etc.). |
|
Generates the API documentation. This target is available only if is enabled. | |
Removes all the object files, libraries and example binaries produced by a previous build. You generally don’t need to invoke this target, the exception being when you want to completely rebuild SFML (some source updates may be incompatible with existing object files and cleaning everything is the only solution). |
|
Installs SFML to the path given by and . It copies over the SFML libraries and headers, as well as examples and documentation if and are enabled. After installing, you get a clean distribution of SFML, just as if you had downloaded the SDK or installed it from your distribution’s package repository. |
If you use an IDE, a target is simply a project. To build a target, select the corresponding project and compile it (even «clean» and
«install» must be built to be executed — don’t be confused by the fact that no source code is actually compiled).
If you use a makefile, pass the name of the target to the make command to build the target. Examples: «», «»,
«».
At this point you should have successfully built SFML. Congratulations!
Custom packets
Packets provide nice features on top of your raw data, but what if you want to add your own features such as automatically compressing or encrypting the data? This can
easily be done by deriving from and overriding the following functions:
- : called before the data is sent by the socket
- : called after the data has been received by the socket
These functions provide direct access to the data, so that you can transform them according to your needs.
Here is a mock-up of a packet that performs automatic compression/decompression:
Such a packet class can be used exactly like . All your operator overloads will apply to them as well.
Установка библиотеки SFML
Я не буду рассказывать, как установить Visual Studio, а перейду сразу к SFML. Для того, чтобы установить библиотеку, нужно зайти на сайт www.sfml-dev.org и перейти в пункт меню «Download» и скачать «SFML 2.5.1»:
Как уже говорилось ранее, в качестве IDE я буду использовать Visual Studio 2017, поэтому скачиваем соответствующую версию SFML. Вы также можете заметить наличие готового пакета для эстетов Code Blocks. Помимо этого, в глаза бросаются варианты библиотеки для других версий Visual Studio. Сразу дам совет — не пытайтесь лепить Франкенштейна, используя неподходящий билд SFML, иначе вы рискуете получить вагон и маленькую тележку всякого рода проблем на свою голову.
Теперь скачанный архив нужно распаковать. У себя я выбрал следующий путь — .
Далее создадим пустой проект и подключим к нему библиотеку SFML. Для этого запустите Visual Studio и выберите , или можно воспользоваться сочетанием горячих клавиш . Задайте имя и расположение проекта так, как показано на следующем скриншоте:
Теперь, когда у нас есть проект, нужно добавить в него файл, который будет содержать исходный код нашей программы. Для этого в окне «Обозреватель решений» клацните ПКМ по строке :
В поле «Имя» укажите :
Отлично! Следующим шагом будет подключение библиотеки SFML к нашему проекту. Для этого нужно:
подключить каталог заголовочных и исходных файлов SFML ();
подключить каталог библиотечных файлов SFML ();
подключить библиотечные файлы SFML в качестве дополнительных зависимостей.
Переходим в :
В верхнем левом углу страницы свойств SFML_Tutorial есть выпадающий список возле пункта , установите его значение как . Также проверьте, что в параметре установлено значение . Затем в левой части окна найдите и выберите раздел
Обратите внимание на правую часть, нас интересует параметр. Выберите его и нажмите
Перед вами появится новое окно, в котором нужно указать путь к заголовочным файлам библиотеки SFML. Обычно они располагаются в папке include. У меня этот путь выглядит как .
Похожим образом подключаются и файлы библиотек. Всё, что нужно сделать — это выбрать в левой части . Затем и . В открывшемся окне нужно будет указать путь к библиотечным файлам SFML, у меня это .
Осталось подключить несколько файлов в виде дополнительных зависимостей для «Компоновщика». Для этого нужно переключить тип конфигурации на , а затем в левой части окна выбрать . Переведите взгляд на правую часть, где нужно найти строку и нажмите . В появившемся окне впишите имена следующих 4 файлов:
Должно получиться следующее:
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.
Packets
The two other problems (endianness and message boundaries) are solved by using a specific class to pack your data: . As a bonus, it provides
a much nicer interface than plain old byte arrays.
Packets have a programming interface similar to standard streams: you can insert data with the << operator, and extract data with the >> operator.
Unlike writing, reading from a packet can fail if you try to extract more bytes than the packet contains. If a reading operation fails, the packet error flag is set.
To check the error flag of a packet, you can test it like a boolean (the same way you do with standard streams):
Sending and receiving packets is as easy as sending/receiving an array of bytes: sockets have an overload of and that directly
accept a .
Packets solve the «message boundaries» problem, which means that when you send a packet on a TCP socket, you receive the exact same packet on the other end, it cannot
contain less bytes, or bytes from the next packet that you send. However, it has a slight drawback: To preserve message boundaries, has to send
some extra bytes along with your data, which implies that you can only receive them with a if you want them to be properly decoded. Simply put,
you can’t send an SFML packet to a non-SFML packet recipient, it has to use an SFML packet for receiving too. Note that this applies to TCP only, UDP is fine since the protocol itself preserves
message boundaries.
◆ openFromMemory()
bool sf::Music::openFromMemory | ( | const void * | data, |
std::size_t | sizeInBytes | ||
) |
Open a music from an audio file in memory.
This function doesn’t start playing the music (call to do so). See the documentation of sf::InputSoundFile for the list of supported formats.
- Warning
- Since the music is not loaded at once but rather streamed continuously, the data buffer must remain accessible until the sf::Music object loads a new music or is destroyed. That is, you can’t deallocate the buffer right after calling this function.
- Parameters
-
data Pointer to the file data in memory sizeInBytes Size of the data to load, in bytes
- Returns
- True if loading succeeded, false if it failed
- See also
- ,
Header Files
C++ header files have the extension and are structured as follows:
- License block
- Opening include guard
- Included headers
- Opening namespace
- One or more of the following:
- Class and type definitions
- Global function declarations
- Nested namespaces
- Closing namespace
- Closing include guard
- Extended comment on the class
Every header file has a unique include guard. Usually it is based on the filename unless the identifier is already used by another file (with the same name).
OS X implementation: There’s a difference between and files. The extension is used for C++ files and has include guards. The files are Objective-C header files and should not be included in a C++ source file. Those files are «ed» and thus don’t require include guards.
Example
For the file , the include guard would look like this:
The inclusion order is as follows:
- SFML headers
- Public headers, sorted alphabetically.
- Private headers, sorted alphabetically.
- Dependency headers, sorted alphabetically.
- Standard library headers, sorted alphabetically.
Before the includes, a comment with the label Headers is added.
OS X implementation: s come last. This block of inclusion is separated by an empty line and follows the same three rules.
Example
In a class, the public interface comes first (usually with constructors and special member functions at the top), followed by protected members and then private data. In a given access-modifier group, static members are grouped together.
- Doxygen documentation is used with the backslash style (e.g. ).
- Everything in the public API should be documented properly.
- The brief documentation phrase doesn’t end with a dot.
- Documentation tags are grouped together by kind, and groups are separated by an empty line.
- An example below illustrates how the brief and full descriptions, parameters and return values are placed inside a documentation block.
- Single line commenting style only (i.e. ), i.e. no .
- Important block comments (e.g. doc) have delimiting lines before and after, each composed of 60 slashes.
- Documentation comments use triple slashes and have an empty line at the end.
- Documentation for attributes or enumeration values use the form . These comments are vertically aligned.
- Header inclusions are preceded by a «Headers» block comment, attributes by «Member data» and typedefs by «Types»
- Class documentation is split into two parts: a first comment is placed right before the class definition and more elaborated documentation is placed at the bottom of the header file. The elaborated documentation block is optional for classes which are not exposed to the user (e.g. classes inside the namespace).
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 .
Managing multiple OpenGL windows
Managing multiple OpenGL windows is not more complicated than managing one, there are just a few things to keep in mind.
OpenGL calls are made on the active context (thus the active window). Therefore if you want to draw to two different windows within the same
program, you have to select which window is active before drawing something. This can be done with the function:
Only one context (window) can be active in a thread, so you don’t need to deactivate a window before activating another one, it is deactivated
automatically. This is how OpenGL works.
Another thing to know is that all the OpenGL contexts created by SFML share their resources. This means that you can create a texture or vertex
buffer with any context active, and use it with any other. This also means that you don’t have to reload all your OpenGL resources when you recreate
your window. Only shareable OpenGL resources can be shared among contexts. An example of an unshareable resource is a vertex array object.
Including and linking OpenGL to your application
OpenGL headers are not the same on every OS. Therefore, SFML provides an «abstract» header that takes care of including the right file for you.
This header includes OpenGL functions, and nothing else. People sometimes think that SFML automatically includes OpenGL extension headers because SFML loads
extensions itself, but it’s an implementation detail. From the user’s point of view, OpenGL extension loading must be handled like any other external library.
You will then need to link your program to the OpenGL library. Unlike what it does with the headers, SFML can’t provide a unified way of linking
OpenGL. Therefore, you need to know which library to link to according to what operating system you’re using («opengl32» on Windows, «GL» on Linux, etc.).
OpenGL functions start with the «gl» prefix. Remember this when you get linker errors, it will help you find which library you forgot to link.
Drawing from threads
SFML supports multi-threaded drawing, and you don’t even have to do anything to make it work. The only thing to remember is to deactivate a window before using it in
another thread. That’s because a window (more precisely its OpenGL context) cannot be active in more than one thread at the same time.
As you can see, you don’t even need to bother with the activation of the window in the rendering thread, SFML does it automatically for you whenever it needs to be done.
Remember to always create the window and handle its events in the main thread for maximum portability. This is explained in the
window tutorial.
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.
Installing SFML
There are different approaches to the installation of SFML on Linux:
- Install it directly from your distribution’s package repository
- Get the source code, build it and install it
- Download the precompiled SDK and manually copy the files
Option 1 is the preferred one; if the version of SFML that you want to install is available in the official repository, then install it using your
package manager. For example, on Debian you would do:
Option 2 requires more work: you need to ensure all of SFML’s dependencies including their development headers are available, make sure CMake is installed, and manually
execute some commands. This will result in a package which is tailored to your system.
If you want to go this way, there’s a dedicated tutorial on
building SFML yourself.
Finally, option 3 is a good choice for quick installation if SFML is not available as an official package. Download the SDK
from the download page, unpack it and copy the files to your
preferred location: either a separate path in your personal folder (like /home/me/sfml), or a standard path (like /usr/local).
If you already had an older version of SFML installed, make sure that it won’t conflict with the new version!
◆ setAttenuation()
|
inherited |
Set the attenuation factor of the sound.
The attenuation is a multiplicative factor which makes the sound more or less loud according to its distance from the listener. An attenuation of 0 will produce a non-attenuated sound, i.e. its volume will always be the same whether it is heard from near or from far. On the other hand, an attenuation value such as 100 will make the sound fade out very quickly as it gets further from the listener. The default value of the attenuation is 1.
- Parameters
-
attenuation New attenuation factor of the sound
- See also
- ,
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:
-
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. -
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. - 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.
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.
◆ create() [1/2]
void sf::Window::create | ( | VideoMode | mode, |
const String & | title, | ||
Uint32 | style = , | ||
const ContextSettings & | settings = | ||
) |
Create (or recreate) the window.
If the window was already created, it closes it first. If style contains Style::Fullscreen, then mode must be a valid video mode.
The fourth parameter is an optional structure specifying advanced OpenGL context settings such as antialiasing, depth-buffer bits, etc.
- Parameters
-
mode Video mode to use (defines the width, height and depth of the rendering area of the window) title Title of the window style Window style, a bitwise OR combination of sf::Style enumerators settings Additional settings for the underlying OpenGL context
The drawing window
To draw the entities provided by the graphics module, you must use a specialized window class: . This class is derived
from , and inherits all its functions. Everything that you’ve learnt about (creation, event handling,
controlling the framerate, mixing with OpenGL, etc.) is applicable to as well.
On top of that, adds high-level functions to help you draw things easily. In this tutorial we’ll focus on two
of these functions: and . They are as simple as their name implies: clears the whole window with
the chosen color, and draws whatever object you pass to it.
Here is what a typical main loop looks like with a render window:
Calling before drawing anything is mandatory, otherwise the contents from previous frames will be present behind anything you draw. The only exception is
when you cover the entire window with what you draw, so that no pixel is not drawn to. In this case you can avoid calling (although
it won’t have a noticeable impact on performance).
Calling is also mandatory, it takes what was drawn since the last call to and displays it on the window.
Indeed, things are not drawn directly to the window, but to a hidden buffer. This buffer is then copied to the window when you call
— this is called double-buffering.
This clear/draw/display cycle is the only good way to draw things. Don’t try other strategies, such as keeping pixels from the previous frame,
«erasing» pixels, or drawing once and calling display multiple times. You’ll get strange results due to double-buffering.
Modern graphics hardware and APIs are really made for repeated clear/draw/display cycles where everything is completely refreshed at each iteration of
the main loop. Don’t be scared to draw 1000 sprites 60 times per second, you’re far below the millions of triangles that your computer can handle.
Detailed Description
Streamed music played from an audio file.
Musics are sounds that are streamed rather than completely loaded in memory.
This is especially useful for compressed musics that usually take hundreds of MB when they are uncompressed: by streaming it instead of loading it entirely, you avoid saturating the memory and have almost no loading delay. This implies that the underlying resource (file, stream or memory buffer) must remain valid for the lifetime of the sf::Music object.
Apart from that, a sf::Music has almost the same features as the sf::SoundBuffer / sf::Sound pair: you can play/pause/stop it, request its parameters (channels, sample rate), change the way it is played (pitch, volume, 3D position, …), etc.
As a sound stream, a music is played in its own thread in order not to block the rest of the program. This means that you can leave the music alone after calling , it will manage itself very well.
Usage example:
sf::Music music;
if (!music.(«music.ogg»))
{
}
music.(0, 1, 10);
music.(2);
music.(50);
music.(true);
music.();
- See also
- sf::Sound, sf::SoundStream
Definition at line of file Music.hpp.