EffectRef SoundEngine::loadEffect(InputSourceRef inputSource)
{
    FMOD_RESULT result = FMOD_OK;
    FMOD::Sound *sound = NULL;
    
    if (inputSource->isFile())
    {
        result = system->createSound(inputSource->getFilePath().c_str(), FMOD_DEFAULT, NULL, &sound);
    }
    else
    {
        auto buffer = inputSource->loadDataSource()->getBuffer();
        
        FMOD_CREATESOUNDEXINFO exinfo;
        memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
        exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);
        exinfo.length = buffer.getDataSize();
        
        result = system->createSound(static_cast<const char*>(buffer.getData()), FMOD_DEFAULT | FMOD_OPENMEMORY, &exinfo, &sound);
    }
    
    if (result)
    {
        throw FMODException(result);
    }
    else
    {
        return make_shared<Effect>(inputSource, sound);
    }
}
 void TextureAtlas::init(InputSourceRef inputSource, bool useMipmap)
 {
     XmlTree doc(inputSource->loadDataSource());
     
     auto texturePath = doc.getChild("TextureAtlas").getAttributeValue<string>("imagePath");
     auto textureSource = inputSource->getSubSource(texturePath);
     
     texture = textureManager.getTexture(textureSource, useMipmap);
     float width = texture->getWidth();
     float height = texture->getHeight();
     
     // ---
     
     for (auto spriteElement = doc.begin("TextureAtlas/sprite"); spriteElement != doc.end(); ++spriteElement)
     {
         auto spritePath = spriteElement->getAttributeValue<string>("n");
         
         auto x = spriteElement->getAttributeValue<float>("x");
         auto y = spriteElement->getAttributeValue<float>("y");
         auto w = spriteElement->getAttributeValue<float>("w");
         auto h = spriteElement->getAttributeValue<float>("h");
         auto rotated = spriteElement->hasAttribute("r");
         
         float ox, oy;
         float ow, oh;
         
         if (rotated)
         {
             oy = spriteElement->getAttributeValue<float>("oX", 0);
             ox = spriteElement->getAttributeValue<float>("oY", 0);
             ow = spriteElement->getAttributeValue<float>("oW", h);
             oh = spriteElement->getAttributeValue<float>("oH", w);
         }
         else
         {
             ox = spriteElement->getAttributeValue<float>("oX", 0);
             oy = spriteElement->getAttributeValue<float>("oY", 0);
             ow = spriteElement->getAttributeValue<float>("oW", w);
             oh = spriteElement->getAttributeValue<float>("oH", h);
         }
         
         float u1 = x / width;
         float v1 = y / height;
         
         float u2 = (x + w) / width;
         float v2 = (y + h) / height;
         
         sprites[spritePath] = make_shared<Sprite>(texture, w, h, ox, oy, ow, oh, rotated, u1, v1, u2, v2);
     }
 }
void XFont::read(InputSourceRef inputSource)
{
    if (inputSource->isFile())
    {
        ifstream in(inputSource->getFilePath().c_str(), ifstream::binary);
        readFromStream(in);
        in.close();
    }
    else
    {
        DataSourceRef resource = inputSource->loadDataSource();
        Buffer &buffer = resource->getBuffer();

        ReadStreamBuffer tmp(buffer);
        istream in(&tmp);
        readFromStream(in);
    }
}
FollowablePath::FollowablePath(InputSourceRef inputSource, int mode)
:
mode(mode)
{
    if (inputSource->isFile())
    {
        ifstream in(inputSource->getFilePath().c_str(), ifstream::binary);
        readFromStream(in);
        in.close();
    }
    else
    {
        DataSourceRef resource = inputSource->loadDataSource();
        Buffer &buffer = resource->getBuffer();
        
        ReadStreamBuffer tmp(buffer);
        istream in(&tmp);
        readFromStream(in);
    }
}
 void FontManager::unload(InputSourceRef inputSource)
 {
     for (auto it = fonts.begin(); it != fonts.end();)
     {
         if (it->first.first == inputSource->getURI())
         {
             it = fonts.erase(it);
         }
         else
         {
             ++it;
         }
     }
     
     discardUnusedTextures();
 }
EffectRef SoundEngine::preloadEffect(InputSourceRef inputSource)
{
    string key = inputSource->getURI();
    auto it = effects.find(key);
    
    if (it == effects.end())
    {
        EffectRef effect = loadEffect(inputSource);
        effects[key] = effect;
        return effect;
    }
    else
    {
        return it->second;
    }
}
 std::shared_ptr<Font> FontManager::getCachedFont(InputSourceRef inputSource, const Font::Properties &properties)
 {
     auto uri = inputSource->getURI();
     
     auto key = make_pair(uri, properties);
     auto it1 = fonts.find(key);
     
     if (it1 != fonts.end())
     {
         return it1->second;
     }
     else
     {
         FontData *data;
         FontTexture *texture;
         auto it2 = fontDataAndTextures.find(uri);
         
         if (it2 == fontDataAndTextures.end())
         {
             FontAtlas *atlas;
             tie(data, atlas) = fetchFontDataAndAtlas(inputSource); // CAN THROW
             
             texture = new FontTexture(atlas, inputSource);
             delete atlas;
             
             fontDataAndTextures[uri] = make_pair(unique_ptr<FontData>(data), unique_ptr<FontTexture>(texture));
         }
         else
         {
             data = it2->second.first.get();
             texture = it2->second.second.get();
         }
         
         auto font = shared_ptr<Font>(new Font(*this, data, texture, properties)); // make_shared WON'T WORK WITH A PROTECTED CONSTRUCTOR
         fonts[key] = font;
         
         return font;
     }
 }
 std::pair<FontData*, FontAtlas*> FontManager::fetchFontDataAndAtlas(InputSourceRef source)
 {
     auto in = source->loadDataSource()->createStream(); // CAN THROW
     
     string version;
     in->readFixedString(&version, 10);
     
     if (version != "XFONT.003")
     {
         throw runtime_error("Font: WRONG FORMAT");
     }
     
     // ---
     
     int glyphCount;
     in->readLittle(&glyphCount);
     
     auto data = new FontData(glyphCount);
     
     in->readLittle(&data->baseSize);
     in->readLittle(&data->height);
     in->readLittle(&data->ascent);
     in->readLittle(&data->descent);
     in->readLittle(&data->spaceAdvance);
     in->readLittle(&data->strikethroughFactor);
     in->readLittle(&data->underlineOffset);
     in->readLittle(&data->lineThickness);
     
     int atlasWidth;
     int atlasHeight;
     int atlasPadding;
     int unitMargin;
     int unitPadding;
     
     in->readLittle(&atlasWidth);
     in->readLittle(&atlasHeight);
     in->readLittle(&atlasPadding);
     in->readLittle(&unitMargin);
     in->readLittle(&unitPadding);
     
     auto atlas = new FontAtlas(atlasWidth, atlasHeight);
     
     for (int i = 0; i < glyphCount; i++)
     {
         int glyphChar;
         int glyphWidth;
         int glyphHeight;
         int glyphLeftExtent;
         int glyphTopExtent;
         int glyphAtlasX;
         int glyphAtlasY;
         
         in->readLittle(&glyphChar);
         data->glyphs[(wchar_t)glyphChar] = i;
         
         in->readLittle(&data->advance[i]);
         in->readLittle(&glyphWidth);
         in->readLittle(&glyphHeight);
         in->readLittle(&glyphLeftExtent);
         in->readLittle(&glyphTopExtent);
         in->readLittle(&glyphAtlasX);
         in->readLittle(&glyphAtlasY);
         
         auto glyphData = new unsigned char[glyphWidth * glyphHeight];
         in->readData(glyphData, glyphWidth * glyphHeight);
         atlas->addGlyph(glyphData, glyphAtlasX + atlasPadding + unitMargin, glyphAtlasY + atlasPadding + unitMargin, glyphWidth, glyphHeight);
         delete[] glyphData;
         
         data->w[i] = glyphWidth + unitPadding * 2;
         data->h[i] = glyphHeight + unitPadding * 2;
         data->le[i] = glyphLeftExtent - unitPadding;
         data->te[i] = glyphTopExtent + unitPadding;
         
         int x = glyphAtlasX + atlasPadding + unitMargin - unitPadding;
         int y = glyphAtlasY + atlasPadding + unitMargin - unitPadding;
         
         data->u1[i] = x / (float)atlasWidth;
         data->v1[i] = y / (float)atlasHeight;
         data->u2[i] = (x + data->w[i]) / (float)atlasWidth;
         data->v2[i] = (y + data->h[i]) / (float)atlasHeight;
     }
     
     return make_pair(data, atlas);
 }