Ce tutoriel vous explique comment charger des images dans un thread, et en afficher la progression.
Le code complet est disponible ici.
Dans ce tutoriel, toutes les images du répertoire “Images/” seront chargées, et la progression ainsi que l'image actuellement en chargement seront affichées.
Une fois le chargement effectué, le nombre d'images chargées avec succès sera affiché.
Jetons donc un coup d'oeil au code.
#include <SFML/System.hpp> #include <SFML/Graphics.hpp> #include <boost/filesystem.hpp> #include <cstring> typedef std::vector<std::string> FileList; typedef FileList::iterator FileListIterator; unsigned int findFiles(FileList& Files, const std::string& Directory) { boost::filesystem::path Dir(Directory); if (!boost::filesystem::exists(Dir)) return 0; boost::filesystem::directory_iterator itEnd; for (boost::filesystem::directory_iterator it(Dir); it != itEnd; ++it) { if (boost::filesystem::is_directory(it->status())) findFiles(Files, it->path().string()); else if (boost::filesystem::is_regular(it->status())) Files.push_back(it->path().string()); else; //Ni un répertoire, ni un fichier régulier } return Files.size(); }
Il s'agit d'une fonction récursive qui crée une liste de tous les fichiers (réguliers) contenus dans un répertoire.
Elle prend comme argument une référence vers une liste de fichiers de classe FileList (cf le typedef) ainsi que le chemin du répertoire dans lequel effectuer la recherche.
Cette fonction nous permet de créer une liste des fichiers contenus dans “Images/”.
boost::filesystem est utilisé.
typedef std::vector<sf::Image*> ImageList; struct LoadingThreadInfo { sf::RenderWindow& Window; //Mutex pour le context OpenGL sf::Mutex& GLMutex; std::string& Filename; //Mutex pour le nom de fichier Filename dans le main() sf::Mutex& FilenameMutex; //Progression (en pourcentage) float& Progress; //Le chargement a-t-il toujours lieu ? bool& Loading; ImageList& Images; };
Il s'agit d'une simple structure, avec les références nécessaires, passée comme argument à la fonction gérant le thread
Il y a un mutex pour OpenGL et un mutex pour le nom de fichier de l'image en cours de chargement.
ImageList est tout bêtement un vecteur de pointeurs de sf::Image.
void LoadImages(void* Data) { LoadingThreadInfo* Info = (LoadingThreadInfo*)Data; sf::RenderWindow& Window = Info->Window; float& Progress = Info->Progress; bool& isLoading = Info->Loading; sf::Mutex& GLMutex = Info->GLMutex; sf::Mutex& FilenameMutex = Info->FilenameMutex; ImageList& Images = Info->Images; std::string& Filename = Info->Filename; FileList ImageFiles; findFiles(ImageFiles, "Images/"); std::size_t numFiles = ImageFiles.size(); printf("Found %d images\n", numFiles); for (std::size_t i = 0; i < numFiles; ++i) { sf::Lock lockGL(GLMutex); Window.SetActive(); FilenameMutex.Lock(); Filename = ImageFiles[i]; FilenameMutex.Unlock(); printf("Loading %s\n", ImageFiles[i].c_str()); sf::Image* newImage = new sf::Image; if (newImage->LoadFromFile(ImageFiles[i])) Images.push_back(newImage); else delete newImage; Progress = static_cast<float>(i + 1) / static_cast<float>(numFiles) * 100.0f; Window.SetActive(false); } isLoading = false; FilenameMutex.Lock(); Filename.clear(); FilenameMutex.Unlock(); }
Il s'agit là de la fonction gérant le thread.
Nous créons une liste des fichiers contenus dans le répertoire “Images/“
Nous essayons ensuite de les charger.
Si le chargement d'une image échoue, nous essayons de charger la suivante.
Remarquez l'appel à SetActive(). Voir ce sujet (en anglais)
Nous devons prendre garde à verrouiller et déverrouiller les mutexs lorsqu'on cherche à accéder à des ressources partagées.
int main(int argc, char* argv[]) { sf::RenderWindow Window(sf::VideoMode(800, 600, 32), "", sf::Style::Close); sf::String ProgressString; sf::String FilenameString; char Buffer[32]; bool isLoading = true; float loadingProgress = 0.0f; std::string Filename; sf::Mutex GLMutex; sf::Mutex FilenameMutex; ImageList Images; LoadingThreadInfo LoadingInfo = {Window, GLMutex, Filename, FilenameMutex, loadingProgress, isLoading, Images}; sf::Thread LoadingThread(&LoadImages, &LoadingInfo); LoadingThread.Launch(); sf::Event Event; bool Done = false; while (!Done) { if (isLoading) { GLMutex.Lock(); Window.SetActive(); } while (Window.GetEvent(Event)) { switch (Event.Type) { case sf::Event::Closed: Done = true; break; } } if (isLoading) { if (Filename.empty()) { FilenameString.SetText("Chargement en cours..."); } else { FilenameMutex.Lock(); FilenameString.SetText("L'image " + Filename + " est en cours de chargement"); FilenameMutex.Unlock(); } sprintf_s(Buffer, sizeof(Buffer), "%.2f%%", loadingProgress); ProgressString.SetText(Buffer); } else { sprintf_s(Buffer, sizeof(Buffer), "%d images ont été chargées avec succès", Images.size()); ProgressString.SetText(Buffer); } ProgressString.SetPosition(400 - ProgressString.GetRect().GetWidth() / 2, 500); Window.Draw(ProgressString); if (!Filename.empty()) { FilenameString.SetPosition(400 - FilenameString.GetRect().GetWidth() / 2, 550); Window.Draw(FilenameString); } Window.Display(); if (isLoading) { Window.SetActive(false); GLMutex.Unlock(); } } for (std::size_t i = 0; i < Images.size(); ++i) delete Images[i]; return 0; }
Pour finir, voici la fonction principale.
Si le thread est en cours d'exécution, la progression actuelle est affichée, ainsi que l'image en cours de chargement.
Sinon, nous affichons le nombre d'image chargées avec succès.
http://www.sendspace.com/file/4am7gy
Ce fichier contient :