Améliorations du gestionnaire de ressources
Le gestionnaire devient un singleton pour faciliter le partage des ressources. Possibilité de charger dans les sous-dossiers. Fonction de listing de tous les fichiers dans un dossier. Adieu au chargement initial pour éviter des problèmes de performance (à tester)
This commit is contained in:
		
							parent
							
								
									f67e95306d
								
							
						
					
					
						commit
						bee32a1fb1
					
				| 
						 | 
				
			
			@ -6,48 +6,83 @@
 | 
			
		|||
#include <boost/filesystem.hpp>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Gestionnaire de ressources du jeu. Conserve des
 | 
			
		||||
 * références vers toutes les ressources pour éviter
 | 
			
		||||
 * de les charger deux fois, permet l'accès uniforme
 | 
			
		||||
 * aux ressources
 | 
			
		||||
 * Gestionnaire de ressources du jeu. La classe agit comme une interface
 | 
			
		||||
 * avec le dossier res/. Elle permet de précharger les ressources gourmandes
 | 
			
		||||
 * telles que les textures ou les polices
 | 
			
		||||
 */
 | 
			
		||||
class ResourceManager {
 | 
			
		||||
private:
 | 
			
		||||
    bool preloaded;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Chemins vers les différents dossiers de ressources
 | 
			
		||||
     */
 | 
			
		||||
    boost::filesystem::path textures_path;
 | 
			
		||||
    boost::filesystem::path fonts_path;
 | 
			
		||||
    boost::filesystem::path levels_path;
 | 
			
		||||
    boost::filesystem::path musics_path;
 | 
			
		||||
 | 
			
		||||
    std::unordered_map<std::string, std::shared_ptr<sf::Image>> images;
 | 
			
		||||
    std::unordered_map<std::string, std::shared_ptr<sf::Texture>> textures;
 | 
			
		||||
    std::unordered_map<std::string, std::shared_ptr<sf::Font>> fonts;
 | 
			
		||||
    sf::Music music;
 | 
			
		||||
    std::unordered_map<
 | 
			
		||||
        boost::filesystem::path,
 | 
			
		||||
        std::shared_ptr<sf::Image>
 | 
			
		||||
    > images_cache;
 | 
			
		||||
 | 
			
		||||
    std::unordered_map<
 | 
			
		||||
        boost::filesystem::path,
 | 
			
		||||
        std::shared_ptr<sf::Texture>
 | 
			
		||||
    > textures_cache;
 | 
			
		||||
 | 
			
		||||
    boost::filesystem::path current_music_path;
 | 
			
		||||
    bool is_playing;
 | 
			
		||||
    sf::Music current_music;
 | 
			
		||||
    float music_volume;
 | 
			
		||||
    bool playing_state;
 | 
			
		||||
    std::string current_music;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    /**
 | 
			
		||||
     * Construit le gestionnaire de ressources. Comme on ne
 | 
			
		||||
     * veut qu'une seule instance du gestionnaire, c'est privé
 | 
			
		||||
     */
 | 
			
		||||
    ResourceManager();
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    /**
 | 
			
		||||
     * Précharge toutes les ressources préchargeables
 | 
			
		||||
     * Renvoie l'unique instance du singleton gestionnaire de ressources
 | 
			
		||||
     */
 | 
			
		||||
    void preload();
 | 
			
		||||
    static ResourceManager& get();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Récupère une image préchargée
 | 
			
		||||
     * Récupère la liste des fichiers dans le dossier donné
 | 
			
		||||
     */
 | 
			
		||||
    std::vector<boost::filesystem::path> getFiles(boost::filesystem::path dir) const;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Récupère le chemin vers le dossier des textures
 | 
			
		||||
     */
 | 
			
		||||
    const boost::filesystem::path& getTexturesPath() const;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Récupère le chemin vers le dossier des polices
 | 
			
		||||
     */
 | 
			
		||||
    const boost::filesystem::path& getFontsPath() const;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Récupère le chemin vers le dossier des niveaux
 | 
			
		||||
     */
 | 
			
		||||
    const boost::filesystem::path& getLevelsPath() const;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Récupère le chemin vers le dossier des musiques
 | 
			
		||||
     */
 | 
			
		||||
    const boost::filesystem::path& getMusicsPath() const;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Charge l'image dont le chemin est donné en paramètre
 | 
			
		||||
     */
 | 
			
		||||
    std::shared_ptr<sf::Image> getImage(std::string name);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Récupère une texture préchargée
 | 
			
		||||
     * Charge l'image dont le chemin est donné en paramètre
 | 
			
		||||
     * et la charge vers le GPU en tant que texture
 | 
			
		||||
     */
 | 
			
		||||
    std::shared_ptr<sf::Texture> getTexture(std::string name);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -57,18 +92,7 @@ public:
 | 
			
		|||
    std::shared_ptr<sf::Font> getFont(std::string name);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Récupère le chemin vers le fichier du niveau portant le
 | 
			
		||||
     * nom passé en argument
 | 
			
		||||
     */
 | 
			
		||||
    std::string getLevelPath(std::string name);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Récupère la liste de tous les niveaux
 | 
			
		||||
     */
 | 
			
		||||
    std::vector<std::string> getLevelList();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Démarre la musique de fond donnée
 | 
			
		||||
     * Joue la musique de fond donnée en paramètre
 | 
			
		||||
     */
 | 
			
		||||
    void playMusic(std::string name);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +104,7 @@ public:
 | 
			
		|||
    /**
 | 
			
		||||
     * Récupère le volume de la musique de fond
 | 
			
		||||
     */
 | 
			
		||||
    float getMusicVolume();
 | 
			
		||||
    float getMusicVolume() const;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Modifie le volume de la musique de fond
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,143 +1,141 @@
 | 
			
		|||
#include "resource_manager.hpp"
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
namespace fs = boost::filesystem;
 | 
			
		||||
 | 
			
		||||
ResourceManager::get() {
 | 
			
		||||
    static ResourceManager manager;
 | 
			
		||||
    return manager;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ResourceManager::ResourceManager() : preloaded(false),
 | 
			
		||||
    music_volume(20), playing_state(false), current_music("") {
 | 
			
		||||
 | 
			
		||||
    // mise en mémoire des chemins vers les dossiers de ressources
 | 
			
		||||
    fs::path res_path = fs::current_path() / "res";
 | 
			
		||||
 | 
			
		||||
    textures_path = res_path / "textures";
 | 
			
		||||
    fonts_path = res_path / "fonts";
 | 
			
		||||
    levels_path = res_path / "levels";
 | 
			
		||||
    musics_path = res_path / "musics";
 | 
			
		||||
 | 
			
		||||
    // initialisation de la musique en bouclage et au volume par défaut
 | 
			
		||||
    music.setLoop(true);
 | 
			
		||||
    music.setVolume(music_volume);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ResourceManager::preload() {
 | 
			
		||||
    if (preloaded) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
std::vector<fs::path> ResourceManager::getFiles(fs::path dir) const {
 | 
			
		||||
    fs::recursive_directory_iterator dir(path), end;
 | 
			
		||||
    std::vector<fs::path> result;
 | 
			
		||||
 | 
			
		||||
    boost::filesystem::path current = boost::filesystem::current_path();
 | 
			
		||||
    boost::filesystem::directory_iterator end;
 | 
			
		||||
 | 
			
		||||
    // on garde une référence aux chemins des différentes ressources
 | 
			
		||||
    textures_path = current / "res/textures";
 | 
			
		||||
    fonts_path = current / "res/fonts";
 | 
			
		||||
    levels_path = current / "res/levels";
 | 
			
		||||
    musics_path = current / "res/musics";
 | 
			
		||||
 | 
			
		||||
    // préchargement de toutes les textures
 | 
			
		||||
    for (boost::filesystem::directory_iterator it(textures_path); it != end; ++it) {
 | 
			
		||||
        if (boost::filesystem::is_regular_file(it->path())) {
 | 
			
		||||
            std::string full_path = boost::filesystem::canonical(it->path()).string();
 | 
			
		||||
            std::string name = it->path().filename().string();
 | 
			
		||||
 | 
			
		||||
            auto image = std::shared_ptr<sf::Image>(new sf::Image);
 | 
			
		||||
            auto texture = std::shared_ptr<sf::Texture>(new sf::Texture);
 | 
			
		||||
            texture->setSmooth(true);
 | 
			
		||||
 | 
			
		||||
            std::cout << "Chargement de l'image " << name << "... ";
 | 
			
		||||
 | 
			
		||||
            if (!image->loadFromFile(full_path)) {
 | 
			
		||||
                std::cerr << "ERREUR!" << std::endl;
 | 
			
		||||
            } else {
 | 
			
		||||
                std::cout << "OK!" << std::endl;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            std::cout << "Mise en mémoire de la texture " << name << "... ";
 | 
			
		||||
 | 
			
		||||
            if (!texture->loadFromImage(*image)) {
 | 
			
		||||
                std::cerr << "ERREUR!" << std::endl;
 | 
			
		||||
            } else {
 | 
			
		||||
                std::cout << "OK!" << std::endl;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            images[name] = std::move(image);
 | 
			
		||||
            textures[name] = std::move(texture);
 | 
			
		||||
    // on boucle sur tous les fichiers du dossier
 | 
			
		||||
    // et de ses sous-dossiers et on les garde en mémoire
 | 
			
		||||
    while (dir != end) {
 | 
			
		||||
        if (fs::is_regular_file(dir->path())) {
 | 
			
		||||
            result.push_back(dir->path());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ++dir;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // préchargement de toutes les polices
 | 
			
		||||
    for (boost::filesystem::directory_iterator it(fonts_path); it != end; ++it) {
 | 
			
		||||
        if (boost::filesystem::is_regular_file(it->path())) {
 | 
			
		||||
            std::string full_path = boost::filesystem::canonical(it->path()).string();
 | 
			
		||||
            std::string name = it->path().filename().string();
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
            auto font = std::shared_ptr<sf::Font>(new sf::Font);
 | 
			
		||||
            std::cout << "Chargement de la police " << name << "... ";
 | 
			
		||||
const fs::path& getTexturesPath() const {
 | 
			
		||||
    return textures_path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
            if (!font->loadFromFile(full_path)) {
 | 
			
		||||
                std::cerr << "ERREUR!" << std::endl;
 | 
			
		||||
            } else {
 | 
			
		||||
                std::cout << "OK!" << std::endl;
 | 
			
		||||
            }
 | 
			
		||||
const fs::path& getFontsPath() const {
 | 
			
		||||
    return fonts_path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
            fonts[name] = std::move(font);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
const fs::path& getLevelsPath() const {
 | 
			
		||||
    return levels_path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    preloaded = true;
 | 
			
		||||
const fs::path& getMusicsPath() const {
 | 
			
		||||
    return musics_path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<sf::Image> ResourceManager::getImage(std::string name) {
 | 
			
		||||
    if (images.count(name) == 0) {
 | 
			
		||||
        throw std::runtime_error(
 | 
			
		||||
            "Impossible de récupérer l'image inexistante : " + name
 | 
			
		||||
        );
 | 
			
		||||
    // si l'image a déjà été chargée, on retourne la
 | 
			
		||||
    // version en cache mémoire
 | 
			
		||||
    if (images_cache.count(name) > 0) {
 | 
			
		||||
        return images_cache[name];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return images[name];
 | 
			
		||||
    fs::path image_path = textures_path / name;
 | 
			
		||||
    std::string full_path = fs::canonical(image_path).string();
 | 
			
		||||
 | 
			
		||||
    // on tente de charger l'image depuis son emplacement
 | 
			
		||||
    auto image = std::shared_ptr<sf::Image>(new sf::Image);
 | 
			
		||||
    std::cout << "Chargement de l'image " << name << " : ";
 | 
			
		||||
 | 
			
		||||
    if (image->loadFromFile(full_path)) {
 | 
			
		||||
        std::cout << "OK!" << std::endl;
 | 
			
		||||
    } else {
 | 
			
		||||
        std::cerr << "ERR!" << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // on met en cache l'image pour les requêtes suivantes
 | 
			
		||||
    // puis on la renvoie
 | 
			
		||||
    images_cache[name] = std::move(image);
 | 
			
		||||
    return images_cache[name];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<sf::Texture> ResourceManager::getTexture(std::string name) {
 | 
			
		||||
    if (textures.count(name) == 0) {
 | 
			
		||||
        throw std::runtime_error(
 | 
			
		||||
            "Impossible de récupérer la texture inexistante : " + name
 | 
			
		||||
        );
 | 
			
		||||
    // si la texture est déjà dans le GPU, on renvoie son pointeur
 | 
			
		||||
    if (textures_cache.count(name) > 0) {
 | 
			
		||||
        return textures_cache[name];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return textures[name];
 | 
			
		||||
    // on récupère l'image depuis le disque
 | 
			
		||||
    std::shared_ptr<sf::Image> image = getImage(name);
 | 
			
		||||
 | 
			
		||||
    // on transfère l'image vers le GPU
 | 
			
		||||
    auto texture = std::shared_ptr<sf::Texture>(new sf::Texture);
 | 
			
		||||
    std::cout << "Création de la texture " << name << " : ";
 | 
			
		||||
 | 
			
		||||
    if (texture->loadFromImage(*image)) {
 | 
			
		||||
        std::cout << "OK!" << std::endl;
 | 
			
		||||
    } else {
 | 
			
		||||
        std::cerr << "ERR!" << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // on met en cache la texture pour les requêtes suivantes
 | 
			
		||||
    // puis on la renvoie
 | 
			
		||||
    textures_cache[name] = std::move(texture);
 | 
			
		||||
    return textures_cache[name];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<sf::Font> ResourceManager::getFont(std::string name) {
 | 
			
		||||
    if (fonts.count(name) == 0) {
 | 
			
		||||
        throw std::runtime_error(
 | 
			
		||||
            "Impossible de récupérer la police inexistante : " + name
 | 
			
		||||
        );
 | 
			
		||||
    // on ne maintient pas de cache pour les polices, car ceci
 | 
			
		||||
    // est géré par la librairie du GUI (SFGUI). On tente de
 | 
			
		||||
    // charger la police depuis le disque
 | 
			
		||||
    fs::path font_path = fonts_path / name;
 | 
			
		||||
    std::string full_path = fs::canonical(font_path).string();
 | 
			
		||||
 | 
			
		||||
    auto font = std::shared_ptr<sf::Font>(new sf::Font);
 | 
			
		||||
    std::cout << "Chargement de la police " << name << ": ";
 | 
			
		||||
 | 
			
		||||
    if (font->loadFromFile(full_path)) {
 | 
			
		||||
        std::cout << "OK!" << std::endl;
 | 
			
		||||
    } else {
 | 
			
		||||
        std::cerr << "ERR!" << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return fonts[name];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string ResourceManager::getLevelPath(std::string name) {
 | 
			
		||||
    return (levels_path / name).string();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<std::string> ResourceManager::getLevelList() {
 | 
			
		||||
    boost::filesystem::directory_iterator iter(levels_path);
 | 
			
		||||
    std::vector<boost::filesystem::path> list;
 | 
			
		||||
    std::vector<std::string> path_list;
 | 
			
		||||
 | 
			
		||||
    // récupération de la liste de tous les niveaux
 | 
			
		||||
    std::copy(
 | 
			
		||||
        iter, boost::filesystem::directory_iterator(),
 | 
			
		||||
        std::back_inserter(list)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // tri par ordre alphabétique
 | 
			
		||||
    std::sort(list.begin(), list.end());
 | 
			
		||||
 | 
			
		||||
    // conversion en chemins absolus
 | 
			
		||||
    for (auto it = list.begin(); it != list.end(); it++) {
 | 
			
		||||
        path_list.push_back((*it).string());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return path_list;
 | 
			
		||||
    return font;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ResourceManager::playMusic(std::string name) {
 | 
			
		||||
    fs::path music_path = musics_path / name;
 | 
			
		||||
 | 
			
		||||
    // si la musique est déjà chargée, on la relance si elle
 | 
			
		||||
    // est en pause, sinon on ne fait rien
 | 
			
		||||
    if (current_music == name) {
 | 
			
		||||
        if (!playing_state) {
 | 
			
		||||
            playing_state = true;
 | 
			
		||||
    if (current_music_path == music_path) {
 | 
			
		||||
        if (!is_playing) {
 | 
			
		||||
            is_playing = true;
 | 
			
		||||
            music.play();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -145,29 +143,26 @@ void ResourceManager::playMusic(std::string name) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // tente de charger la musique depuis le dossier "res/musics"
 | 
			
		||||
    std::string full_path = boost::filesystem::canonical(musics_path / name).string();
 | 
			
		||||
    std::string full_path = fs::canonical(music_path).string();
 | 
			
		||||
    std::cout << "Lecture de la musique " << name << "... ";
 | 
			
		||||
 | 
			
		||||
    if (!music.openFromFile(full_path)) {
 | 
			
		||||
        std::cerr << "ERREUR!" << std::endl;
 | 
			
		||||
    } else {
 | 
			
		||||
    if (music.openFromFile(full_path)) {
 | 
			
		||||
        std::cout << "OK!" << std::endl;
 | 
			
		||||
    } else {
 | 
			
		||||
        std::cerr << "ERR!" << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    current_music = name;
 | 
			
		||||
    playing_state = true;
 | 
			
		||||
    current_music_path = music_path;
 | 
			
		||||
    is_playing = true;
 | 
			
		||||
    music.play();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ResourceManager::stopMusic() {
 | 
			
		||||
    // on n'arrête la musique que si elle ne l'est pas déjà
 | 
			
		||||
    if (playing_state) {
 | 
			
		||||
        playing_state = false;
 | 
			
		||||
        music.stop();
 | 
			
		||||
    }
 | 
			
		||||
    is_playing = false;
 | 
			
		||||
    music.stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float ResourceManager::getMusicVolume() {
 | 
			
		||||
float ResourceManager::getMusicVolume() const {
 | 
			
		||||
    return music_volume;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue