This is a quick tutorial on how to load images in a thread and show progress.
The full code is here: loadimagesinthread.cpp
It will load all images in the „Images/“ directory, displaying the progress and the currently loading image.
When it's done loading, it will show how many images were succesfully loaded.
Okay let's look at the 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; //Not a directory or regular file } return Files.size(); }
This is a recursive function to build a list of all (regular) files in a directory.
It takes a reference to a FileList (see the typedef) and the directory to start searching in.
We use this function to build a list of files in „Images/“.
It uses boost::filesystem: http://www.boost.org/doc/libs
typedef std::vector<sf::Image*> ImageList; struct LoadingThreadInfo { sf::RenderWindow& Window; //Mutex for OpenGL context sf::Mutex& GLMutex; std::string& Filename; //Mutex for Filename in main() sf::Mutex& FilenameMutex; //Progress (percentage) float& Progress; //Are we still loading? bool& Loading; ImageList& Images; };
This is a simple struct that is passed to the thread function with necessary references.
We have a mutex for OpenGL and a mutex for the filename of the image currently being loaded.
ImageList is simply a vector of sf::Image pointers.
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(); }
This is the actual thread function.
We build a list of files in the „Images/“ directory.
Then we attempt to load them.
If we fail to load an image, we continue on to the next.
Note the call to SetActive. See this thread: http://sfml-dev.org/forum/viewtopic.php?t=349
We must be careful to lock and unlock our mutexes when we need to access shared data.
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("Loading..."); } else { FilenameMutex.Lock(); FilenameString.SetText("Loading " + Filename); FilenameMutex.Unlock(); } sprintf_s(Buffer, sizeof(Buffer), "%.2f%%", loadingProgress); ProgressString.SetText(Buffer); } else { sprintf_s(Buffer, sizeof(Buffer), "Succesfully loaded %d images", 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; }
Lastly, here's the main function.
If the thread is still loading, we display the progress and the currently loading file.
Otherwise, we display the number of succesfully loaded images.
http://www.sendspace.com/file/4am7gy
This download contains: