Added a new InputStream interface, and LoadFromStream functions to resource classes

This commit is contained in:
Laurent Gomila 2011-07-17 12:21:47 +02:00
parent 73665bd50a
commit c5276ff30a
16 changed files with 736 additions and 192 deletions

View File

@ -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
////////////////////////////////////////////////////////////

View File

@ -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,

View File

@ -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:

View File

@ -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
///

View File

@ -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
///

View File

@ -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>

View 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
///
////////////////////////////////////////////////////////////

View File

@ -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;
}
// Compute the duration
myDuration = static_cast<Uint32>(1000 * myFile->GetSamplesCount() / myFile->GetSampleRate() / myFile->GetChannelsCount());
// Perform common initializations
Initialize();
// Resize the internal buffer so that it can contain 1 second of audio samples
mySamples.resize(myFile->GetSampleRate() * myFile->GetChannelsCount());
return true;
}
// Initialize the stream
Initialize(myFile->GetChannelsCount(), myFile->GetSampleRate());
////////////////////////////////////////////////////////////
bool Music::OpenFromStream(InputStream& stream)
{
// First stop the music if it was already running
Stop();
// 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

View File

@ -80,62 +80,33 @@ 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)
{
// Update the internal buffer with the new samples
return Update(channelsCount, sampleRate);
}
////////////////////////////////////////////////////////////
bool SoundBuffer::LoadFromStream(InputStream& stream)
{
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;
}

View File

@ -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

View File

@ -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

View File

@ -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,7 +61,8 @@ namespace sf
Font::Font() :
myLibrary (NULL),
myFace (NULL),
myRefCount(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();

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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
///

View 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)
{