Added a new InputStream interface, and LoadFromStream functions to resource classes
This commit is contained in:
parent
73665bd50a
commit
c5276ff30a
@ -41,6 +41,8 @@ namespace priv
|
||||
class SoundFile;
|
||||
}
|
||||
|
||||
class InputStream;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Streamed music played from an audio file
|
||||
///
|
||||
@ -74,7 +76,7 @@ public :
|
||||
///
|
||||
/// \return True if loading succeeded, false if it failed
|
||||
///
|
||||
/// \see OpenFromMemory
|
||||
/// \see OpenFromMemory, OpenFromStream
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool OpenFromFile(const std::string& filename);
|
||||
@ -93,11 +95,29 @@ public :
|
||||
///
|
||||
/// \return True if loading succeeded, false if it failed
|
||||
///
|
||||
/// \see OpenFromFile
|
||||
/// \see OpenFromFile, OpenFromStream
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool OpenFromMemory(const void* data, std::size_t sizeInBytes);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Open a music from an audio file in a custom stream
|
||||
///
|
||||
/// This function doesn't start playing the music (call Play()
|
||||
/// to do so).
|
||||
/// Here is a complete list of all the supported audio formats:
|
||||
/// ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
|
||||
/// w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
|
||||
///
|
||||
/// \param stream Source stream to read from
|
||||
///
|
||||
/// \return True if loading succeeded, false if it failed
|
||||
///
|
||||
/// \see OpenFromFile, OpenFromMemory
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool OpenFromStream(InputStream& stream);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the total duration of the music
|
||||
///
|
||||
@ -131,6 +151,12 @@ protected :
|
||||
|
||||
private :
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Initialize the internal state after loading a new music
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void Initialize();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -37,7 +37,13 @@
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
class SoundFile;
|
||||
}
|
||||
|
||||
class Sound;
|
||||
class InputStream;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Storage for audio samples defining a sound
|
||||
@ -78,7 +84,7 @@ public :
|
||||
///
|
||||
/// \return True if loading succeeded, false if it failed
|
||||
///
|
||||
/// \see LoadFromMemory, LoadFromSamples, SaveToFile
|
||||
/// \see LoadFromMemory, LoadFromStream, LoadFromSamples, SaveToFile
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadFromFile(const std::string& filename);
|
||||
@ -95,11 +101,27 @@ public :
|
||||
///
|
||||
/// \return True if loading succeeded, false if it failed
|
||||
///
|
||||
/// \see LoadFromFile, LoadFromSamples, SaveToFile
|
||||
/// \see LoadFromFile, LoadFromStream, LoadFromSamples
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadFromMemory(const void* data, std::size_t sizeInBytes);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load the sound buffer from a custom stream
|
||||
///
|
||||
/// Here is a complete list of all the supported audio formats:
|
||||
/// ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
|
||||
/// w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
|
||||
///
|
||||
/// \param stream Source stream to read from
|
||||
///
|
||||
/// \return True if loading succeeded, false if it failed
|
||||
///
|
||||
/// \see LoadFromFile, LoadFromMemory, LoadFromSamples
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadFromStream(InputStream& stream);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load the sound buffer from an array of audio samples
|
||||
///
|
||||
@ -212,6 +234,16 @@ private :
|
||||
|
||||
friend class Sound;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Initialize the internal state after loading a new sound
|
||||
///
|
||||
/// \param file Sound file providing access to the new loaded sound
|
||||
///
|
||||
/// \return True on succesful initialization, false on failure
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Initialize(priv::SoundFile& file);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update the internal buffer with the cached audio samples
|
||||
///
|
||||
@ -273,9 +305,9 @@ private :
|
||||
/// a sf::Image.
|
||||
///
|
||||
/// A sound buffer can be loaded from a file (see LoadFromFile()
|
||||
/// for the complete list of supported formats), from memory
|
||||
/// or directly from an array of samples. It can also be saved
|
||||
/// back to a file.
|
||||
/// for the complete list of supported formats), from memory, from
|
||||
/// a custom stream (see sf::InputStream) or directly from an array
|
||||
/// of samples. It can also be saved back to a file.
|
||||
///
|
||||
/// Sound buffers alone are not very useful: they hold the audio data
|
||||
/// but cannot be played. To do so, you need to use the sf::Sound class,
|
||||
|
@ -41,6 +41,8 @@
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class InputStream;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Class for loading and manipulating character fonts
|
||||
///
|
||||
@ -86,7 +88,7 @@ public :
|
||||
///
|
||||
/// \return True if loading succeeded, false if it failed
|
||||
///
|
||||
/// \see LoadFromMemory
|
||||
/// \see LoadFromMemory, LoadFromStream
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadFromFile(const std::string& filename);
|
||||
@ -96,9 +98,6 @@ public :
|
||||
///
|
||||
/// The supported font formats are: TrueType, Type 1, CFF,
|
||||
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
|
||||
/// Note that this function know nothing about the standard
|
||||
/// fonts installed on the user's system, thus you can't
|
||||
/// load them directly.
|
||||
/// Warning: SFML cannot preload all the font data in this
|
||||
/// function, so the buffer pointed by \a data has to remain
|
||||
/// valid as long as the font is used.
|
||||
@ -108,11 +107,29 @@ public :
|
||||
///
|
||||
/// \return True if loading succeeded, false if it failed
|
||||
///
|
||||
/// \see LoadFromFile
|
||||
/// \see LoadFromFile, LoadFromStream
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadFromMemory(const void* data, std::size_t sizeInBytes);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load the font from a custom stream
|
||||
///
|
||||
/// The supported font formats are: TrueType, Type 1, CFF,
|
||||
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
|
||||
/// Warning: SFML cannot preload all the font data in this
|
||||
/// function, so the contents of \a stream have to remain
|
||||
/// valid as long as the font is used.
|
||||
///
|
||||
/// \param stream Source stream to read from
|
||||
///
|
||||
/// \return True if loading succeeded, false if it failed
|
||||
///
|
||||
/// \see LoadFromFile, LoadFromMemory
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadFromStream(InputStream& stream);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Retrieve a glyph of the font
|
||||
///
|
||||
@ -278,6 +295,7 @@ private :
|
||||
////////////////////////////////////////////////////////////
|
||||
void* myLibrary; ///< Pointer to the internal library interface (it is typeless to avoid exposing implementation details)
|
||||
void* myFace; ///< Pointer to the internal font face (it is typeless to avoid exposing implementation details)
|
||||
void* myStreamRec; ///< Pointer to the stream rec instance (it is typeless to avoid exposing implementation details)
|
||||
int* myRefCount; ///< Reference counter used by implicit sharing
|
||||
mutable PageTable myPages; ///< Table containing the glyphs pages by character size
|
||||
mutable std::vector<Uint8> myPixelBuffer; ///< Pixel buffer holding a glyph's pixels before being written to the texture
|
||||
@ -293,9 +311,9 @@ private :
|
||||
/// \class sf::Font
|
||||
/// \ingroup graphics
|
||||
///
|
||||
/// Fonts can be loaded from a file or from memory, from
|
||||
/// the most common types of fonts. See the LoadFromFile
|
||||
/// function for the complete list of supported formats.
|
||||
/// Fonts can be loaded from a file, from memory or from a custom
|
||||
/// stream, and supports the most common types of fonts. See
|
||||
/// the LoadFromFile function for the complete list of supported formats.
|
||||
///
|
||||
/// Once it is loaded, a sf::Font instance provides three
|
||||
/// types of informations about the font:
|
||||
|
@ -41,6 +41,7 @@ namespace sf
|
||||
class Renderer;
|
||||
class RenderImage;
|
||||
class RenderWindow;
|
||||
class InputStream;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Class for loading, manipulating and saving images
|
||||
@ -86,7 +87,7 @@ public :
|
||||
///
|
||||
/// \return True if loading was successful
|
||||
///
|
||||
/// \see LoadFromMemory, LoadFromPixels, SaveToFile
|
||||
/// \see LoadFromMemory, LoadFromStream, LoadFromPixels, SaveToFile
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadFromFile(const std::string& filename);
|
||||
@ -106,11 +107,30 @@ public :
|
||||
///
|
||||
/// \return True if loading was successful
|
||||
///
|
||||
/// \see LoadFromFile, LoadFromPixels, SaveToFile
|
||||
/// \see LoadFromFile, LoadFromStream, LoadFromPixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadFromMemory(const void* data, std::size_t size);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load the image from a custom stream
|
||||
///
|
||||
/// The supported image formats are bmp, png, tga, jpg, gif,
|
||||
/// psd, hdr and pic. Some format options are not supported,
|
||||
/// like progressive jpeg.
|
||||
/// The maximum size for an image depends on the graphics
|
||||
/// driver and can be retrieve with the GetMaximumSize function.
|
||||
/// If this function fails, the image is left unchanged.
|
||||
///
|
||||
/// \param stream Source stream to read from
|
||||
///
|
||||
/// \return True if loading was successful
|
||||
///
|
||||
/// \see LoadFromFile, LoadFromMemory, LoadFromPixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadFromStream(InputStream& stream);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load the image from an array of pixels
|
||||
///
|
||||
|
@ -84,7 +84,7 @@ public :
|
||||
///
|
||||
/// \return True if loading succeeded, false if it failed
|
||||
///
|
||||
/// \see LoadFromMemory
|
||||
/// \see LoadFromMemory, LoadFromStream
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadFromFile(const std::string& filename);
|
||||
@ -101,11 +101,28 @@ public :
|
||||
///
|
||||
/// \return True if loading succeeded, false if it failed
|
||||
///
|
||||
/// \see LoadFromFile
|
||||
/// \see LoadFromFile, LoadFromStream
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadFromMemory(const std::string& shader);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load the shader from a custom stream
|
||||
///
|
||||
/// The source code must be a valid fragment shader in
|
||||
/// GLSL language. GLSL is a C-like language dedicated
|
||||
/// to OpenGL shaders; you'll probably need to read a
|
||||
/// good documentation for it before writing your own shaders.
|
||||
///
|
||||
/// \param stream Source stream to read from
|
||||
///
|
||||
/// \return True if loading succeeded, false if it failed
|
||||
///
|
||||
/// \see LoadFromFile, LoadFromMemory
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadFromStream(InputStream& stream);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change a float parameter of the shader
|
||||
///
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <SFML/Config.hpp>
|
||||
#include <SFML/System/Clock.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <SFML/System/InputStream.hpp>
|
||||
#include <SFML/System/Lock.hpp>
|
||||
#include <SFML/System/Mutex.hpp>
|
||||
#include <SFML/System/Sleep.hpp>
|
||||
|
148
include/SFML/System/InputStream.hpp
Normal file
148
include/SFML/System/InputStream.hpp
Normal file
@ -0,0 +1,148 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_INPUTSTREAM_HPP
|
||||
#define SFML_INPUTSTREAM_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Config.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Abstract class for custom file input streams
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class SFML_API InputStream
|
||||
{
|
||||
public :
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Virtual destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual ~InputStream() {}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Read data from the stream
|
||||
///
|
||||
/// \param data Buffer where to copy the read data
|
||||
/// \param size Desired number of bytes to read
|
||||
///
|
||||
/// \return The number of bytes actually read
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Int64 Read(char* data, Int64 size) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the current reading position
|
||||
///
|
||||
/// \param position The position to seek to, from the beginning
|
||||
///
|
||||
/// \return The position actually seeked to, or -1 on error
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Int64 Seek(Int64 position) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Return the current reading position in the stream
|
||||
///
|
||||
/// \return The current position, or -1 on error.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Int64 GetPosition() = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Return the size of the stream
|
||||
///
|
||||
/// \return The total number of bytes available in the stream, or -1 on error
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Int64 GetSize() = 0;
|
||||
};
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_INPUTSTREAM_HPP
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \class sf::InputStream
|
||||
/// \ingroup system
|
||||
///
|
||||
/// This class allows users to define their own file input sources
|
||||
/// from which SFML can load resources.
|
||||
///
|
||||
/// SFML resource classes like sf::Image and
|
||||
/// sf::SoundBuffer provide LoadFromFile and LoadFromMemory functions,
|
||||
/// which read data from conventional sources. However, if you
|
||||
/// have data coming from a different source (over a network,
|
||||
/// embedded, encrypted, compressed, etc) you can derive your
|
||||
/// own class from sf::InputStream and load SFML resources with
|
||||
/// their LoadFromStream function.
|
||||
///
|
||||
/// Usage example:
|
||||
/// \code
|
||||
/// // custom stream class that reads from inside a zip file
|
||||
/// class ZipStream : public sf::InputStream
|
||||
/// {
|
||||
/// public :
|
||||
///
|
||||
/// ZipStream(std::string archive);
|
||||
///
|
||||
/// bool Open(std::string filename);
|
||||
///
|
||||
/// Int64 Read(char* data, Int64 size);
|
||||
///
|
||||
/// Int64 Seek(Int64 position);
|
||||
///
|
||||
/// Int64 GetPosition();
|
||||
///
|
||||
/// Int64 GetSize();
|
||||
///
|
||||
/// private :
|
||||
///
|
||||
/// ...
|
||||
/// };
|
||||
///
|
||||
/// // now you can load images...
|
||||
/// sf::Image image;
|
||||
/// ZipStream stream("resources.zip");
|
||||
/// stream.Open("images/img.png");
|
||||
/// image.LoadFromStream(stream);
|
||||
///
|
||||
/// // musics...
|
||||
/// sf::Music music;
|
||||
/// ZipStream stream("resources.zip");
|
||||
/// stream.Open("musics/msc.ogg");
|
||||
/// music.OpenFromStream(stream);
|
||||
///
|
||||
/// // etc.
|
||||
/// \endcode
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
@ -60,21 +60,12 @@ bool Music::OpenFromFile(const std::string& filename)
|
||||
// First stop the music if it was already running
|
||||
Stop();
|
||||
|
||||
// Create the sound file implementation, and open it in read mode
|
||||
// Open the underlying sound file
|
||||
if (!myFile->OpenRead(filename))
|
||||
{
|
||||
Err() << "Failed to open \"" << filename << "\" for reading" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute the duration
|
||||
myDuration = static_cast<Uint32>(1000 * myFile->GetSamplesCount() / myFile->GetSampleRate() / myFile->GetChannelsCount());
|
||||
|
||||
// Resize the internal buffer so that it can contain 1 second of audio samples
|
||||
mySamples.resize(myFile->GetSampleRate() * myFile->GetChannelsCount());
|
||||
|
||||
// Initialize the stream
|
||||
Initialize(myFile->GetChannelsCount(), myFile->GetSampleRate());
|
||||
// Perform common initializations
|
||||
Initialize();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -86,21 +77,29 @@ bool Music::OpenFromMemory(const void* data, std::size_t sizeInBytes)
|
||||
// First stop the music if it was already running
|
||||
Stop();
|
||||
|
||||
// Create the sound file implementation, and open it in read mode
|
||||
// Open the underlying sound file
|
||||
if (!myFile->OpenRead(data, sizeInBytes))
|
||||
{
|
||||
Err() << "Failed to open music from memory for reading" << std::endl;
|
||||
return false;
|
||||
|
||||
// Perform common initializations
|
||||
Initialize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Compute the duration
|
||||
myDuration = static_cast<Uint32>(1000 * myFile->GetSamplesCount() / myFile->GetSampleRate() / myFile->GetChannelsCount());
|
||||
|
||||
// Resize the internal buffer so that it can contain 1 second of audio samples
|
||||
mySamples.resize(myFile->GetSampleRate() * myFile->GetChannelsCount());
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Music::OpenFromStream(InputStream& stream)
|
||||
{
|
||||
// First stop the music if it was already running
|
||||
Stop();
|
||||
|
||||
// Initialize the stream
|
||||
Initialize(myFile->GetChannelsCount(), myFile->GetSampleRate());
|
||||
// Open the underlying sound file
|
||||
if (!myFile->OpenRead(stream))
|
||||
return false;
|
||||
|
||||
// Perform common initializations
|
||||
Initialize();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -127,8 +126,6 @@ bool Music::OnGetData(SoundStream::Chunk& data)
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// /see SoundStream::OnSeek
|
||||
////////////////////////////////////////////////////////////
|
||||
void Music::OnSeek(Uint32 timeOffset)
|
||||
{
|
||||
@ -137,4 +134,18 @@ void Music::OnSeek(Uint32 timeOffset)
|
||||
myFile->Seek(timeOffset);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Music::Initialize()
|
||||
{
|
||||
// Compute the music duration
|
||||
myDuration = static_cast<Uint32>(1000 * myFile->GetSamplesCount() / myFile->GetSampleRate() / myFile->GetChannelsCount());
|
||||
|
||||
// Resize the internal buffer so that it can contain 1 second of audio samples
|
||||
mySamples.resize(myFile->GetSampleRate() * myFile->GetChannelsCount());
|
||||
|
||||
// Initialize the stream
|
||||
SoundStream::Initialize(myFile->GetChannelsCount(), myFile->GetSampleRate());
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
@ -80,63 +80,34 @@ SoundBuffer::~SoundBuffer()
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundBuffer::LoadFromFile(const std::string& filename)
|
||||
{
|
||||
// Open the sound file
|
||||
priv::SoundFile file;
|
||||
if (file.OpenRead(filename))
|
||||
{
|
||||
// Get the sound parameters
|
||||
std::size_t nbSamples = file.GetSamplesCount();
|
||||
unsigned int channelsCount = file.GetChannelsCount();
|
||||
unsigned int sampleRate = file.GetSampleRate();
|
||||
|
||||
// Read the samples from the opened file
|
||||
mySamples.resize(nbSamples);
|
||||
if (file.Read(&mySamples[0], nbSamples) == nbSamples)
|
||||
{
|
||||
// Update the internal buffer with the new samples
|
||||
return Update(channelsCount, sampleRate);
|
||||
}
|
||||
return Initialize(file);
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundBuffer::LoadFromMemory(const void* data, std::size_t sizeInBytes)
|
||||
{
|
||||
// Open the sound file
|
||||
priv::SoundFile file;
|
||||
if (file.OpenRead(data, sizeInBytes))
|
||||
{
|
||||
// Get the sound parameters
|
||||
std::size_t nbSamples = file.GetSamplesCount();
|
||||
unsigned int channelsCount = file.GetChannelsCount();
|
||||
unsigned int sampleRate = file.GetSampleRate();
|
||||
return Initialize(file);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the samples from the opened file
|
||||
mySamples.resize(nbSamples);
|
||||
if (file.Read(&mySamples[0], nbSamples) == nbSamples)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundBuffer::LoadFromStream(InputStream& stream)
|
||||
{
|
||||
// Update the internal buffer with the new samples
|
||||
return Update(channelsCount, sampleRate);
|
||||
}
|
||||
priv::SoundFile file;
|
||||
if (file.OpenRead(stream))
|
||||
return Initialize(file);
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -153,11 +124,11 @@ bool SoundBuffer::LoadFromSamples(const Int16* samples, std::size_t samplesCount
|
||||
else
|
||||
{
|
||||
// Error...
|
||||
Err() << "Failed to load sound buffer from memory ("
|
||||
<< "Samples : " << samples << ", "
|
||||
<< "Samples count : " << samplesCount << ", "
|
||||
<< "Channels count : " << channelsCount << ", "
|
||||
<< "Sample rate : " << sampleRate << ")"
|
||||
Err() << "Failed to load sound buffer from samples ("
|
||||
<< "array: " << samples << ", "
|
||||
<< "count: " << samplesCount << ", "
|
||||
<< "channels: " << channelsCount << ", "
|
||||
<< "samplerate: " << sampleRate << ")"
|
||||
<< std::endl;
|
||||
|
||||
return false;
|
||||
@ -239,6 +210,28 @@ SoundBuffer& SoundBuffer::operator =(const SoundBuffer& right)
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundBuffer::Initialize(priv::SoundFile& file)
|
||||
{
|
||||
// Retrieve the sound parameters
|
||||
std::size_t nbSamples = file.GetSamplesCount();
|
||||
unsigned int channelsCount = file.GetChannelsCount();
|
||||
unsigned int sampleRate = file.GetSampleRate();
|
||||
|
||||
// Read the samples from the provided file
|
||||
mySamples.resize(nbSamples);
|
||||
if (file.Read(&mySamples[0], nbSamples) == nbSamples)
|
||||
{
|
||||
// Update the internal buffer with the new samples
|
||||
return Update(channelsCount, sampleRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundBuffer::Update(unsigned int channelsCount, unsigned int sampleRate)
|
||||
{
|
||||
@ -252,7 +245,7 @@ bool SoundBuffer::Update(unsigned int channelsCount, unsigned int sampleRate)
|
||||
// Check if the format is valid
|
||||
if (format == 0)
|
||||
{
|
||||
Err() << "Unsupported number of channels (" << channelsCount << ")" << std::endl;
|
||||
Err() << "Failed to load sound buffer (unsupported number of channels: " << channelsCount << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,25 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Audio/SoundFile.hpp>
|
||||
#include <SFML/System/InputStream.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Private data
|
||||
////////////////////////////////////////////////////////////
|
||||
namespace
|
||||
{
|
||||
// Convert a string to lower case
|
||||
std::string ToLower(std::string str)
|
||||
{
|
||||
for (std::string::iterator i = str.begin(); i != str.end(); ++i)
|
||||
*i = static_cast<char>(std::tolower(*i));
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
@ -86,7 +103,7 @@ bool SoundFile::OpenRead(const std::string& filename)
|
||||
myFile = sf_open(filename.c_str(), SFM_READ, &fileInfos);
|
||||
if (!myFile)
|
||||
{
|
||||
Err() << "Failed to read sound file \"" << filename << "\" (" << sf_strerror(myFile) << ")" << std::endl;
|
||||
Err() << "Failed to open sound file \"" << filename << "\" (" << sf_strerror(myFile) << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -107,14 +124,55 @@ bool SoundFile::OpenRead(const void* data, std::size_t sizeInBytes)
|
||||
sf_close(myFile);
|
||||
|
||||
// Prepare the memory I/O structure
|
||||
SF_VIRTUAL_IO io = myMemoryIO.Prepare(data, sizeInBytes);
|
||||
SF_VIRTUAL_IO io;
|
||||
io.get_filelen = &Memory::GetLength;
|
||||
io.read = &Memory::Read;
|
||||
io.seek = &Memory::Seek;
|
||||
io.tell = &Memory::Tell;
|
||||
|
||||
// Initialize the memory data
|
||||
myMemory.DataStart = static_cast<const char*>(data);
|
||||
myMemory.DataPtr = myMemory.DataStart;
|
||||
myMemory.TotalSize = sizeInBytes;
|
||||
|
||||
// Open the sound file
|
||||
SF_INFO fileInfos;
|
||||
myFile = sf_open_virtual(&io, SFM_READ, &fileInfos, &myMemoryIO);
|
||||
myFile = sf_open_virtual(&io, SFM_READ, &fileInfos, &myMemory);
|
||||
if (!myFile)
|
||||
{
|
||||
Err() << "Failed to read sound file from memory (" << sf_strerror(myFile) << ")" << std::endl;
|
||||
Err() << "Failed to open sound file from memory (" << sf_strerror(myFile) << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the sound parameters
|
||||
myChannelsCount = fileInfos.channels;
|
||||
mySampleRate = fileInfos.samplerate;
|
||||
myNbSamples = static_cast<std::size_t>(fileInfos.frames) * myChannelsCount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundFile::OpenRead(InputStream& stream)
|
||||
{
|
||||
// If the file is already opened, first close it
|
||||
if (myFile)
|
||||
sf_close(myFile);
|
||||
|
||||
// Prepare the memory I/O structure
|
||||
SF_VIRTUAL_IO io;
|
||||
io.get_filelen = &Stream::GetLength;
|
||||
io.read = &Stream::Read;
|
||||
io.seek = &Stream::Seek;
|
||||
io.tell = &Stream::Tell;
|
||||
|
||||
// Open the sound file
|
||||
SF_INFO fileInfos;
|
||||
myFile = sf_open_virtual(&io, SFM_READ, &fileInfos, &stream);
|
||||
if (!myFile)
|
||||
{
|
||||
Err() << "Failed to open sound file from stream (" << sf_strerror(myFile) << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -215,120 +273,125 @@ int SoundFile::GetFormatFromFilename(const std::string& filename)
|
||||
ext = filename.substr(pos + 1);
|
||||
|
||||
// Match every supported extension with its format constant
|
||||
if (ext == "wav" || ext == "WAV" ) return SF_FORMAT_WAV;
|
||||
if (ext == "aif" || ext == "AIF" ) return SF_FORMAT_AIFF;
|
||||
if (ext == "aiff" || ext == "AIFF") return SF_FORMAT_AIFF;
|
||||
if (ext == "au" || ext == "AU" ) return SF_FORMAT_AU;
|
||||
if (ext == "raw" || ext == "RAW" ) return SF_FORMAT_RAW;
|
||||
if (ext == "paf" || ext == "PAF" ) return SF_FORMAT_PAF;
|
||||
if (ext == "svx" || ext == "SVX" ) return SF_FORMAT_SVX;
|
||||
if (ext == "nist" || ext == "NIST") return SF_FORMAT_NIST;
|
||||
if (ext == "voc" || ext == "VOC" ) return SF_FORMAT_VOC;
|
||||
if (ext == "sf" || ext == "SF" ) return SF_FORMAT_IRCAM;
|
||||
if (ext == "w64" || ext == "W64" ) return SF_FORMAT_W64;
|
||||
if (ext == "mat4" || ext == "MAT4") return SF_FORMAT_MAT4;
|
||||
if (ext == "mat5" || ext == "MAT5") return SF_FORMAT_MAT5;
|
||||
if (ext == "pvf" || ext == "PVF" ) return SF_FORMAT_PVF;
|
||||
if (ext == "xi" || ext == "XI" ) return SF_FORMAT_XI;
|
||||
if (ext == "htk" || ext == "HTK" ) return SF_FORMAT_HTK;
|
||||
if (ext == "sds" || ext == "SDS" ) return SF_FORMAT_SDS;
|
||||
if (ext == "avr" || ext == "AVR" ) return SF_FORMAT_AVR;
|
||||
if (ext == "sd2" || ext == "SD2" ) return SF_FORMAT_SD2;
|
||||
if (ext == "flac" || ext == "FLAC") return SF_FORMAT_FLAC;
|
||||
if (ext == "caf" || ext == "CAF" ) return SF_FORMAT_CAF;
|
||||
if (ext == "wve" || ext == "WVE" ) return SF_FORMAT_WVE;
|
||||
if (ext == "ogg" || ext == "OGG") return SF_FORMAT_OGG;
|
||||
if (ext == "mpc2k" || ext == "MPC2K") return SF_FORMAT_MPC2K;
|
||||
if (ext == "rf64" || ext == "RF64") return SF_FORMAT_RF64;
|
||||
if (ToLower(ext) == "wav" ) return SF_FORMAT_WAV;
|
||||
if (ToLower(ext) == "aif" ) return SF_FORMAT_AIFF;
|
||||
if (ToLower(ext) == "aiff" ) return SF_FORMAT_AIFF;
|
||||
if (ToLower(ext) == "au" ) return SF_FORMAT_AU;
|
||||
if (ToLower(ext) == "raw" ) return SF_FORMAT_RAW;
|
||||
if (ToLower(ext) == "paf" ) return SF_FORMAT_PAF;
|
||||
if (ToLower(ext) == "svx" ) return SF_FORMAT_SVX;
|
||||
if (ToLower(ext) == "nist" ) return SF_FORMAT_NIST;
|
||||
if (ToLower(ext) == "voc" ) return SF_FORMAT_VOC;
|
||||
if (ToLower(ext) == "sf" ) return SF_FORMAT_IRCAM;
|
||||
if (ToLower(ext) == "w64" ) return SF_FORMAT_W64;
|
||||
if (ToLower(ext) == "mat4" ) return SF_FORMAT_MAT4;
|
||||
if (ToLower(ext) == "mat5" ) return SF_FORMAT_MAT5;
|
||||
if (ToLower(ext) == "pvf" ) return SF_FORMAT_PVF;
|
||||
if (ToLower(ext) == "xi" ) return SF_FORMAT_XI;
|
||||
if (ToLower(ext) == "htk" ) return SF_FORMAT_HTK;
|
||||
if (ToLower(ext) == "sds" ) return SF_FORMAT_SDS;
|
||||
if (ToLower(ext) == "avr" ) return SF_FORMAT_AVR;
|
||||
if (ToLower(ext) == "sd2" ) return SF_FORMAT_SD2;
|
||||
if (ToLower(ext) == "flac" ) return SF_FORMAT_FLAC;
|
||||
if (ToLower(ext) == "caf" ) return SF_FORMAT_CAF;
|
||||
if (ToLower(ext) == "wve" ) return SF_FORMAT_WVE;
|
||||
if (ToLower(ext) == "ogg" ) return SF_FORMAT_OGG;
|
||||
if (ToLower(ext) == "mpc2k") return SF_FORMAT_MPC2K;
|
||||
if (ToLower(ext) == "rf64" ) return SF_FORMAT_RF64;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
SF_VIRTUAL_IO SoundFile::MemoryIO::Prepare(const void* data, std::size_t sizeInBytes)
|
||||
sf_count_t SoundFile::Memory::GetLength(void* user)
|
||||
{
|
||||
// Setup the I/O functions
|
||||
SF_VIRTUAL_IO io;
|
||||
io.get_filelen = &SoundFile::MemoryIO::GetLength;
|
||||
io.read = &SoundFile::MemoryIO::Read;
|
||||
io.seek = &SoundFile::MemoryIO::Seek;
|
||||
io.tell = &SoundFile::MemoryIO::Tell;
|
||||
io.write = &SoundFile::MemoryIO::Write;
|
||||
|
||||
// Initialize the memory data
|
||||
myDataStart = static_cast<const char*>(data);
|
||||
myDataPtr = myDataStart;
|
||||
myTotalSize = sizeInBytes;
|
||||
|
||||
return io;
|
||||
Memory* memory = static_cast<Memory*>(user);
|
||||
return memory->TotalSize;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
sf_count_t SoundFile::MemoryIO::GetLength(void* userData)
|
||||
sf_count_t SoundFile::Memory::Read(void* ptr, sf_count_t count, void* user)
|
||||
{
|
||||
MemoryIO* self = static_cast<MemoryIO*>(userData);
|
||||
Memory* memory = static_cast<Memory*>(user);
|
||||
|
||||
return self->myTotalSize;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
sf_count_t SoundFile::MemoryIO::Read(void* ptr, sf_count_t count, void* userData)
|
||||
{
|
||||
MemoryIO* self = static_cast<MemoryIO*>(userData);
|
||||
|
||||
sf_count_t position = self->myDataPtr - self->myDataStart;
|
||||
if (position + count >= self->myTotalSize)
|
||||
count = self->myTotalSize - position;
|
||||
|
||||
std::memcpy(ptr, self->myDataPtr, static_cast<std::size_t>(count));
|
||||
|
||||
self->myDataPtr += count;
|
||||
sf_count_t position = memory->DataPtr - memory->DataStart;
|
||||
if (position + count >= memory->TotalSize)
|
||||
count = memory->TotalSize - position;
|
||||
|
||||
std::memcpy(ptr, memory->DataPtr, static_cast<std::size_t>(count));
|
||||
memory->DataPtr += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
sf_count_t SoundFile::MemoryIO::Seek(sf_count_t offset, int whence, void* userData)
|
||||
sf_count_t SoundFile::Memory::Seek(sf_count_t offset, int whence, void* user)
|
||||
{
|
||||
MemoryIO* self = static_cast<MemoryIO*>(userData);
|
||||
|
||||
Memory* memory = static_cast<Memory*>(user);
|
||||
sf_count_t position = 0;
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET : position = offset; break;
|
||||
case SEEK_CUR : position = self->myDataPtr - self->myDataStart + offset; break;
|
||||
case SEEK_END : position = self->myTotalSize - offset; break;
|
||||
case SEEK_CUR : position = memory->DataPtr - memory->DataStart + offset; break;
|
||||
case SEEK_END : position = memory->TotalSize - offset; break;
|
||||
default : position = 0; break;
|
||||
}
|
||||
|
||||
if (position >= self->myTotalSize)
|
||||
position = self->myTotalSize - 1;
|
||||
if (position >= memory->TotalSize)
|
||||
position = memory->TotalSize - 1;
|
||||
else if (position < 0)
|
||||
position = 0;
|
||||
|
||||
self->myDataPtr = self->myDataStart + position;
|
||||
|
||||
memory->DataPtr = memory->DataStart + position;
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
sf_count_t SoundFile::MemoryIO::Tell(void* userData)
|
||||
sf_count_t SoundFile::Memory::Tell(void* user)
|
||||
{
|
||||
MemoryIO* self = static_cast<MemoryIO*>(userData);
|
||||
|
||||
return self->myDataPtr - self->myDataStart;
|
||||
Memory* memory = static_cast<Memory*>(user);
|
||||
return memory->DataPtr - memory->DataStart;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
sf_count_t SoundFile::MemoryIO::Write(const void*, sf_count_t, void*)
|
||||
sf_count_t SoundFile::Stream::GetLength(void* userData)
|
||||
{
|
||||
return 0;
|
||||
sf::InputStream* stream = static_cast<sf::InputStream*>(userData);
|
||||
return stream->GetSize();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
sf_count_t SoundFile::Stream::Read(void* ptr, sf_count_t count, void* userData)
|
||||
{
|
||||
sf::InputStream* stream = static_cast<sf::InputStream*>(userData);
|
||||
return stream->Read(reinterpret_cast<char*>(ptr), count);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
sf_count_t SoundFile::Stream::Seek(sf_count_t offset, int whence, void* userData)
|
||||
{
|
||||
sf::InputStream* stream = static_cast<sf::InputStream*>(userData);
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET : return stream->Seek(offset);
|
||||
case SEEK_CUR : return stream->Seek(stream->GetPosition() + offset);
|
||||
case SEEK_END : return stream->Seek(stream->GetSize() - offset);
|
||||
default : return stream->Seek(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
sf_count_t SoundFile::Stream::Tell(void* userData)
|
||||
{
|
||||
sf::InputStream* stream = static_cast<sf::InputStream*>(userData);
|
||||
return stream->GetPosition();
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
@ -35,6 +35,8 @@
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class InputStream;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -102,6 +104,16 @@ public :
|
||||
////////////////////////////////////////////////////////////
|
||||
bool OpenRead(const void* data, std::size_t sizeInBytes);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Open a sound file from a custom stream for reading
|
||||
///
|
||||
/// \param stream Source stream to read from
|
||||
///
|
||||
/// \return True if the file was successfully opened
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool OpenRead(InputStream& stream);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief a the sound file for writing
|
||||
///
|
||||
@ -156,33 +168,38 @@ private :
|
||||
static int GetFormatFromFilename(const std::string& filename);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Provide I/O functions for manipulating files in memory
|
||||
/// \brief Data and callbacks for opening from memory
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class MemoryIO
|
||||
struct Memory
|
||||
{
|
||||
public :
|
||||
const char* DataStart;
|
||||
const char* DataPtr;
|
||||
sf_count_t TotalSize;
|
||||
|
||||
SF_VIRTUAL_IO Prepare(const void* data, std::size_t sizeInBytes);
|
||||
static sf_count_t GetLength(void* user);
|
||||
static sf_count_t Read(void* ptr, sf_count_t count, void* user);
|
||||
static sf_count_t Seek(sf_count_t offset, int whence, void* user);
|
||||
static sf_count_t Tell(void* user);
|
||||
};
|
||||
|
||||
private :
|
||||
|
||||
static sf_count_t GetLength(void* userData);
|
||||
static sf_count_t Read(void* ptr, sf_count_t count, void* userData);
|
||||
static sf_count_t Seek(sf_count_t offset, int whence, void* userData);
|
||||
static sf_count_t Tell(void* userData);
|
||||
static sf_count_t Write(const void* ptr, sf_count_t count, void* userData);
|
||||
|
||||
const char* myDataStart;
|
||||
const char* myDataPtr;
|
||||
sf_count_t myTotalSize;
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Callbacks for opening from stream
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
struct Stream
|
||||
{
|
||||
static sf_count_t GetLength(void* user);
|
||||
static sf_count_t Read(void* ptr, sf_count_t count, void* user);
|
||||
static sf_count_t Seek(sf_count_t offset, int whence, void* user);
|
||||
static sf_count_t Tell(void* user);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
SNDFILE* myFile; ///< File descriptor
|
||||
MemoryIO myMemoryIO; ///< Memory read / write data
|
||||
Memory myMemory; ///< Memory reading info
|
||||
std::size_t myNbSamples; ///< Total number of samples in the file
|
||||
unsigned int myChannelsCount; ///< Number of channels used by the sound
|
||||
unsigned int mySampleRate; ///< Number of samples per second
|
||||
|
@ -26,12 +26,33 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Font.hpp>
|
||||
#include <SFML/System/InputStream.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_GLYPH_H
|
||||
#include FT_OUTLINE_H
|
||||
#include FT_BITMAP_H
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Private data
|
||||
////////////////////////////////////////////////////////////
|
||||
namespace
|
||||
{
|
||||
// FreeType callbacks that operate on a sf::InputStream
|
||||
unsigned long Read(FT_Stream rec, unsigned long offset, unsigned char* buffer, unsigned long count)
|
||||
{
|
||||
sf::InputStream* stream = static_cast<sf::InputStream*>(rec->descriptor.pointer);
|
||||
if (stream->Seek(offset) != offset)
|
||||
return count ? 1 : 0; // error code is 0 if we're reading, or nonzero if we're seeking
|
||||
return static_cast<unsigned long>(stream->Read(reinterpret_cast<char*>(buffer), count));
|
||||
}
|
||||
void Close(FT_Stream)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
@ -40,6 +61,7 @@ namespace sf
|
||||
Font::Font() :
|
||||
myLibrary (NULL),
|
||||
myFace (NULL),
|
||||
myStreamRec(NULL),
|
||||
myRefCount (NULL)
|
||||
{
|
||||
|
||||
@ -51,6 +73,7 @@ Font::Font(const Font& copy) :
|
||||
Resource<Font>(),
|
||||
myLibrary (copy.myLibrary),
|
||||
myFace (copy.myFace),
|
||||
myStreamRec (copy.myStreamRec),
|
||||
myRefCount (copy.myRefCount),
|
||||
myPages (copy.myPages),
|
||||
myPixelBuffer(copy.myPixelBuffer)
|
||||
@ -150,6 +173,63 @@ bool Font::LoadFromMemory(const void* data, std::size_t sizeInBytes)
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Font::LoadFromStream(InputStream& stream)
|
||||
{
|
||||
// Cleanup the previous resources
|
||||
Cleanup();
|
||||
myRefCount = new int(1);
|
||||
|
||||
// Initialize FreeType
|
||||
// Note: we initialize FreeType for every font instance in order to avoid having a single
|
||||
// global manager that would create a lot of issues regarding creation and destruction order.
|
||||
FT_Library library;
|
||||
if (FT_Init_FreeType(&library) != 0)
|
||||
{
|
||||
Err() << "Failed to load font from stream (failed to initialize FreeType)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
myLibrary = library;
|
||||
|
||||
// Prepare a wrapper for our stream, that we'll pass to FreeType callbacks
|
||||
FT_StreamRec* rec = new FT_StreamRec;
|
||||
std::memset(rec, 0, sizeof(rec));
|
||||
rec->base = NULL;
|
||||
rec->size = static_cast<unsigned long>(stream.GetSize());
|
||||
rec->pos = 0;
|
||||
rec->descriptor.pointer = &stream;
|
||||
rec->read = &Read;
|
||||
rec->close = &Close;
|
||||
|
||||
// Setup the FreeType callbacks that will read our stream
|
||||
FT_Open_Args args;
|
||||
args.flags = FT_OPEN_STREAM;
|
||||
args.stream = rec;
|
||||
args.driver = 0;
|
||||
|
||||
// Load the new font face from the specified stream
|
||||
FT_Face face;
|
||||
if (FT_Open_Face(static_cast<FT_Library>(myLibrary), &args, 0, &face) != 0)
|
||||
{
|
||||
Err() << "Failed to load font from stream (failed to create the font face)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Select the unicode character map
|
||||
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0)
|
||||
{
|
||||
Err() << "Failed to load font from stream (failed to set the Unicode character set)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the loaded font in our ugly void* :)
|
||||
myFace = face;
|
||||
myStreamRec = rec;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Glyph& Font::GetGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) const
|
||||
{
|
||||
@ -284,6 +364,10 @@ void Font::Cleanup()
|
||||
if (myFace)
|
||||
FT_Done_Face(static_cast<FT_Face>(myFace));
|
||||
|
||||
// Destroy the stream rec instance, if any (must be done after FT_Done_Face!)
|
||||
if (myStreamRec)
|
||||
delete static_cast<FT_StreamRec*>(myStreamRec);
|
||||
|
||||
// Close the library
|
||||
if (myLibrary)
|
||||
FT_Done_FreeType(static_cast<FT_Library>(myLibrary));
|
||||
@ -293,6 +377,7 @@ void Font::Cleanup()
|
||||
// Reset members
|
||||
myLibrary = NULL;
|
||||
myFace = NULL;
|
||||
myStreamRec = NULL;
|
||||
myRefCount = NULL;
|
||||
myPages.clear();
|
||||
myPixelBuffer.clear();
|
||||
|
@ -136,6 +136,28 @@ bool Image::LoadFromMemory(const void* data, std::size_t size)
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Image::LoadFromStream(InputStream& stream)
|
||||
{
|
||||
// Forward the job to the image loader
|
||||
std::vector<Uint8> pixels;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
if (priv::ImageLoader::GetInstance().LoadImageFromStream(stream, pixels, width, height))
|
||||
{
|
||||
// Loading succeeded : we can create the texture
|
||||
if (CreateTexture(width, height))
|
||||
{
|
||||
// Copy the pixels
|
||||
myPixels.swap(pixels);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Image::LoadFromPixels(unsigned int width, unsigned int height, const Uint8* data)
|
||||
{
|
||||
|
@ -26,6 +26,7 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/ImageLoader.hpp>
|
||||
#include <SFML/System/InputStream.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <SFML/Graphics/stb_image/stb_image.h>
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
@ -38,6 +39,9 @@ extern "C"
|
||||
#include <cctype>
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Private data
|
||||
////////////////////////////////////////////////////////////
|
||||
namespace
|
||||
{
|
||||
// Convert a string to lower case
|
||||
@ -47,6 +51,23 @@ namespace
|
||||
*i = static_cast<char>(std::tolower(*i));
|
||||
return str;
|
||||
}
|
||||
|
||||
// stb_image callbacks that operate on a sf::InputStream
|
||||
int Read(void* user, char* data, int size)
|
||||
{
|
||||
sf::InputStream* stream = static_cast<sf::InputStream*>(user);
|
||||
return static_cast<int>(stream->Read(data, size));
|
||||
}
|
||||
void Skip(void* user, unsigned int size)
|
||||
{
|
||||
sf::InputStream* stream = static_cast<sf::InputStream*>(user);
|
||||
stream->Seek(stream->GetPosition() + size);
|
||||
}
|
||||
int Eof(void* user)
|
||||
{
|
||||
sf::InputStream* stream = static_cast<sf::InputStream*>(user);
|
||||
return stream->GetPosition() >= stream->GetSize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -157,6 +178,47 @@ bool ImageLoader::LoadImageFromMemory(const void* data, std::size_t size, std::v
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool ImageLoader::LoadImageFromStream(InputStream& stream, std::vector<Uint8>& pixels, unsigned int& width, unsigned int& height)
|
||||
{
|
||||
// Clear the array (just in case)
|
||||
pixels.clear();
|
||||
|
||||
// Setup the stb_image callbacks
|
||||
stbi_io_callbacks callbacks;
|
||||
callbacks.read = &Read;
|
||||
callbacks.skip = &Skip;
|
||||
callbacks.eof = &Eof;
|
||||
|
||||
// Load the image and get a pointer to the pixels in memory
|
||||
int imgWidth, imgHeight, imgChannels;
|
||||
unsigned char* ptr = stbi_load_from_callbacks(&callbacks, &stream, &imgWidth, &imgHeight, &imgChannels, STBI_rgb_alpha);
|
||||
|
||||
if (ptr && imgWidth && imgHeight)
|
||||
{
|
||||
// Assign the image properties
|
||||
width = imgWidth;
|
||||
height = imgHeight;
|
||||
|
||||
// Copy the loaded pixels to the pixel buffer
|
||||
pixels.resize(width * height * 4);
|
||||
memcpy(&pixels[0], ptr, pixels.size());
|
||||
|
||||
// Free the loaded pixels (they are now in our own pixel buffer)
|
||||
stbi_image_free(ptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error, failed to load the image
|
||||
Err() << "Failed to load image from stream. Reason : " << stbi_failure_reason() << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool ImageLoader::SaveImageToFile(const std::string& filename, const std::vector<Uint8>& pixels, unsigned int width, unsigned int height)
|
||||
{
|
||||
|
@ -35,6 +35,8 @@
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class InputStream;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -67,7 +69,7 @@ public :
|
||||
bool LoadImageFromFile(const std::string& filename, std::vector<Uint8>& pixels, unsigned int& width, unsigned int& height);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load an image from a file inn memory
|
||||
/// \brief Load an image from a file in memory
|
||||
///
|
||||
/// \param data Pointer to the file data in memory
|
||||
/// \param size Size of the data to load, in bytes
|
||||
@ -80,6 +82,19 @@ public :
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadImageFromMemory(const void* data, std::size_t size, std::vector<Uint8>& pixels, unsigned int& width, unsigned int& height);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load an image from a custom stream
|
||||
///
|
||||
/// \param stream Source stream to read from
|
||||
/// \param pixels Array of pixels to fill with loaded image
|
||||
/// \param width Width of loaded image, in pixels
|
||||
/// \param height Height of loaded image, in pixels
|
||||
///
|
||||
/// \return True if loading was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool LoadImageFromStream(InputStream& stream, std::vector<Uint8>& pixels, unsigned int& width, unsigned int& height);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \bref Save an array of pixels as an image file
|
||||
///
|
||||
|
@ -28,9 +28,10 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Shader.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/System/InputStream.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace sf
|
||||
@ -100,6 +101,19 @@ bool Shader::LoadFromMemory(const std::string& shader)
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Shader::LoadFromStream(InputStream& stream)
|
||||
{
|
||||
// Read the shader code from the stream
|
||||
std::vector<char> buffer(static_cast<std::size_t>(stream.GetSize()));
|
||||
Int64 read = stream.Read(&buffer[0], buffer.size());
|
||||
myFragmentShader.assign(&buffer[0], &buffer[0] + read);
|
||||
|
||||
// Create the shaders and the program
|
||||
return CompileProgram();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shader::SetParameter(const std::string& name, float x)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user