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

@ -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);
}
else
{
return false;
}
}
return Initialize(file);
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();
// 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);
}
else
{
return false;
}
}
return Initialize(file);
else
return false;
}
////////////////////////////////////////////////////////////
bool SoundBuffer::LoadFromStream(InputStream& stream)
{
priv::SoundFile file;
if (file.OpenRead(stream))
return Initialize(file);
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,21 +26,43 @@
// 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
{
////////////////////////////////////////////////////////////
Font::Font() :
myLibrary (NULL),
myFace (NULL),
myRefCount(NULL)
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));
@ -291,9 +375,10 @@ void Font::Cleanup()
}
// Reset members
myLibrary = NULL;
myFace = NULL;
myRefCount = NULL;
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)
{