📜 ⬆️ ⬇️

2.3 Working with custom data streams



Translator: This article is the eighth in the translation cycle of the official SFML library guide. Past article can be found here. This series of articles aims to provide people who do not know the original language the opportunity to get acquainted with this library. SFML is a simple and cross-platform multimedia library. SFML provides a simple interface for developing games and other multimedia applications. The original article can be found here . Let's start.

Table of contents:
0.1 Introduction

1. Getting Started
')
  1. SFML and Visual Studio
  2. SFML and Code :: Blocks (MinGW)
  3. SFML and Linux
  4. SFML and Xcode (Mac OS X)
  5. Compiling SFML with CMake

2. System Module

  1. Processing time
  2. Streams
  3. Work with custom data streams

3. Window Module

  1. Opening and managing windows
  2. Event handling
  3. Work with the keyboard, mouse and joysticks
  4. Using OpenGL

4. Graphics Module

  1. Drawing 2D objects
  2. Sprites and textures
  3. Text and Fonts
  4. Forms
  5. Designing your own objects using arrays of vertices
  6. Position, Rotation, Scale: Transform Objects
  7. Adding special effects with shaders
  8. 2D camera control and view

5. Audio module

  1. Playing sounds and music
  2. Audio recording
  3. Custom audio streams
  4. Spitalization: sounds in 3D

6. Network module

  1. Socket communication
  2. Use and Expansion Packages
  3. Web requests using HTTP
  4. File Transfer Using FTP


Introduction


SFML has resource classes (images, fonts, sounds, etc.). In many programs, these resources will be loaded from files using the loadFromFile function. In some situations, resources will be directly packed into an executable file or into a large data file and will be loaded from memory using the loadFromMemory function. These functions can satisfy almost any need, but not all.

You may want to download files from an unusual place, such as a compressed / encrypted archive, or, for example, from a remote network folder. For these special situations, SFML provides a third function: loadFromStream . This function reads data using the abstract sf :: InputStream interface, which allows you to have your own implementation of a stream class that will work with SFML.

This article will explain how to write and use your own thread classes.

Standard C ++ threads?


Like many other languages, C ++ already contains a data flow class: std::istream . In fact, there are two such classes: std::istream is only a front-end solution, an abstract interface to data obtained from std::streambuf .

Unfortunately, these classes are not user friendly - solving a non-trivial task using these classes can become very difficult. The Boost.Iostreams library aims to provide a simple interface for standard streams, but Boost is a big dependency.

For this reason, SFML provides its own stream class, which we hope is simpler and faster than the ones listed above.

InputStream


The sf :: InputStream class declares four virtual functions:

 class InputStream { public : virtual ~InputStream() {} virtual Int64 read(void* data, Int64 size) = 0; virtual Int64 seek(Int64 position) = 0; virtual Int64 tell() = 0; virtual Int64 getSize() = 0; }; 

read should extract size bytes from the stream and copy them to the provided address. Returns the number of bytes read, or -1 if an error occurred.

seek should change the current position in the stream. The argument is the absolute number of bytes to move (the count comes from the beginning of the data area, not from the current position). Returns the new position or -1 if an error occurred.

tell must return the current position (the number of bytes from the beginning of the data area) in the stream or -1 in case of an error.

getSize should return the size (in bytes) of the data block contained in the stream, or -1 if an error occurs.

To create your own working thread, you must include in your thread class an implementation of each of these four functions that will meet the requirements described above.

FileInputStream and MemoryInputStream


Two new classes have been added to SFML 2.3, providing streams for managing the new audio module. sf::FileInputStream provides a stream for reading a file, sf::MemoryInputStream is used to read a stream of data from memory. Both classes are based on sf :: InputStream and can be used polymorphically.

Using InputStream


Using a custom stream class is simple: instantiate it and pass it as an argument to the loadFromStream (or openFromStream ) function of the object you want to initialize as a stream.

 sf::FileStream stream; stream.open("image.png"); sf::Texture texture; texture.loadFromStream(stream); 

Examples


If you need a demonstration of working code, and you do not want to get lost in the implementation details, you can take a look at the sf::FileInputStream and sf::MemoryInputStream .

Do not forget to check the forum and wiki. There is a chance that another user has already written a class that meets your needs. If you have written a new class and consider that it may be useful to other users, do not hesitate to share it!

Common Misconceptions


Some resource classes do not load completely after calling loadFromStream . Instead, they continue to read data from the data source for as long as required. For this reason, the sf :: Music class reads audio primitives through the stream during their playback, and the sf :: Font class loads glyphs when the need arises.

As a result, the stream you use to download a music or font, as well as the data source, must exist for as long as these resources are used. Destruction of the source of information or class of data flow leads to indefinite behavior (the program can complete its execution, damage the data, or nothing can happen).

Another common misconception is that the function returns an invalid value, i.e. values ​​that SFML is not expected to return in this situation. For example, for sf::FileInputStream you could write a search function as follows:

 sf::Int64 FileInputStream::seek(sf::Int64 position) { return std::fseek(m_file, position, SEEK_SET); } 

However, this code is not correct, because std::fseek returns zero on success, while SFML expects a new position in the stream to return.

Next article: Opening and managing windows .

Source: https://habr.com/ru/post/279689/


All Articles