Skip to content

Commit

Permalink
#5911: Add file sorting functionality to ThreadedDefLoader. ShaderFil…
Browse files Browse the repository at this point in the history
…eLoader and ParticleLoader are subclassing the ThreadedDefLoader.

Compiling and working, but some parse code still needs to be migrated.
  • Loading branch information
codereader committed Mar 2, 2022
1 parent fcadac2 commit 689e06d
Show file tree
Hide file tree
Showing 19 changed files with 318 additions and 231 deletions.
52 changes: 49 additions & 3 deletions libs/ThreadedDefLoader.h
Expand Up @@ -2,6 +2,9 @@

#include <future>
#include <functional>
#include <algorithm>
#include <vector>
#include "ifilesystem.h"

namespace util
{
Expand All @@ -16,10 +19,18 @@ namespace util
*
* Client code (even from multiple threads) can retrieve (and wait for) the result
* by calling the get() method.
*
* The loader will invoke the functor passed to the constructor for each encountered
* def file, in the same order as the idTech4/TDM engine (alphabetically).
*/
template <typename ReturnType>
class ThreadedDefLoader
{
private:
std::string _baseDir;
std::string _extension;
std::size_t _depth;

typedef std::function<ReturnType()> LoadFunction;

LoadFunction _loadFunc;
Expand All @@ -32,11 +43,19 @@ class ThreadedDefLoader
bool _loadingStarted;

public:
ThreadedDefLoader(const LoadFunction& loadFunc) :
ThreadedDefLoader(loadFunc, std::function<void()>())
ThreadedDefLoader(const std::string& baseDir, const std::string& extension, const LoadFunction& loadFunc) :
ThreadedDefLoader(baseDir, extension, 0, loadFunc)
{}

ThreadedDefLoader(const std::string& baseDir, const std::string& extension, std::size_t depth, const LoadFunction& loadFunc) :
ThreadedDefLoader(baseDir, extension, depth, loadFunc, std::function<void()>())
{}

ThreadedDefLoader(const LoadFunction& loadFunc, const std::function<void()>& finishedFunc) :
ThreadedDefLoader(const std::string& baseDir, const std::string& extension, std::size_t depth,
const LoadFunction& loadFunc, const std::function<void()>& finishedFunc) :
_baseDir(baseDir),
_extension(extension),
_depth(depth),
_loadFunc(loadFunc),
_finishedFunc(finishedFunc),
_loadingStarted(false)
Expand Down Expand Up @@ -101,6 +120,33 @@ class ThreadedDefLoader
}
}

protected:
void loadFiles(const vfs::VirtualFileSystem::VisitorFunc& visitor)
{
loadFiles(GlobalFileSystem(), visitor);
}

void loadFiles(vfs::VirtualFileSystem& vfs, const vfs::VirtualFileSystem::VisitorFunc& visitor)
{
// Accumulate all the files and sort them before calling the visitor
std::vector<vfs::FileInfo> _incomingFiles;
_incomingFiles.reserve(200);

vfs.forEachFile(_baseDir, _extension, [&](const vfs::FileInfo& info)
{
_incomingFiles.push_back(info);
}, _depth);

// Sort the files by name
std::sort(_incomingFiles.begin(), _incomingFiles.end(), [](const vfs::FileInfo& a, const vfs::FileInfo& b)
{
return a.name < b.name;
});

// Dispatch the sorted list to the visitor
std::for_each(_incomingFiles.begin(), _incomingFiles.end(), visitor);
}

private:
struct FinishFunctionCaller
{
Expand Down
2 changes: 1 addition & 1 deletion plugins/dm.gui/gui/GuiManager.cpp
Expand Up @@ -11,7 +11,7 @@ namespace gui
{

GuiManager::GuiManager() :
_guiLoader(std::bind(&GuiManager::findGuis, this))
_guiLoader(GUI_DIR, GUI_EXT, std::bind(&GuiManager::findGuis, this))
{}

void GuiManager::registerGui(const std::string& guiPath)
Expand Down
2 changes: 1 addition & 1 deletion plugins/sound/SoundManager.cpp
Expand Up @@ -63,7 +63,7 @@ ArchiveFilePtr openSoundFile(const std::string& fileName)

// Constructor
SoundManager::SoundManager() :
_defLoader(std::bind(&SoundManager::loadShadersFromFilesystem, this)),
_defLoader(SOUND_FOLDER, "sndshd", 99, std::bind(&SoundManager::loadShadersFromFilesystem, this)),
_emptyShader(new SoundShader("", "",
vfs::FileInfo("sounds/", "_autogenerated_by_darkradiant_.sndshd", vfs::Visibility::HIDDEN), ""))
{}
Expand Down
1 change: 1 addition & 0 deletions radiantcore/CMakeLists.txt
Expand Up @@ -194,6 +194,7 @@ add_library(radiantcore MODULE
modulesystem/ModuleLoader.cpp
modulesystem/ModuleRegistry.cpp
particles/ParticleDef.cpp
particles/ParticleLoader.cpp
particles/ParticleNode.cpp
particles/ParticleParameter.cpp
particles/ParticlesManager.cpp
Expand Down
2 changes: 1 addition & 1 deletion radiantcore/eclass/EClassManager.cpp
Expand Up @@ -24,7 +24,7 @@ namespace eclass {
// Constructor
EClassManager::EClassManager() :
_realised(false),
_defLoader(std::bind(&EClassManager::loadDefAndResolveInheritance, this),
_defLoader("def/", "def", 1, std::bind(&EClassManager::loadDefAndResolveInheritance, this),
std::bind(&EClassManager::onDefLoadingCompleted, this)),
_curParseStamp(0)
{}
Expand Down
13 changes: 10 additions & 3 deletions radiantcore/fonts/FontLoader.cpp
Expand Up @@ -11,10 +11,10 @@
namespace fonts
{

void FontLoader::operator()(const vfs::FileInfo& fileInfo)
void FontLoader::loadFont(const vfs::FileInfo& fileInfo)
{
// Construct the full VFS path
std::string fullPath = os::standardPath(_basePath + fileInfo.name);
std::string fullPath = fileInfo.fullPath();

std::regex expr("^/?(.*)/.*_(\\d{2})\\.dat$", std::regex::icase);
std::smatch matches;
Expand Down Expand Up @@ -45,7 +45,7 @@ void FontLoader::operator()(const vfs::FileInfo& fileInfo)
if (resolution != NumResolutions)
{
// Create the font (if not done yet), acquire the info structure
FontInfoPtr font = _manager.findOrCreateFontInfo(fontname);
auto font = _manager.findOrCreateFontInfo(fontname);

// Load the DAT file and create the glyph info
font->glyphSets[resolution] = GlyphSet::createFromDatFile(
Expand All @@ -59,4 +59,11 @@ void FontLoader::operator()(const vfs::FileInfo& fileInfo)
}
}

void FontLoader::loadFonts()
{
loadFiles(std::bind(&FontLoader::loadFont, this, std::placeholders::_1));

rMessage() << _manager.getNumFonts() << " fonts registered." << std::endl;
}

} // namespace fonts
22 changes: 14 additions & 8 deletions radiantcore/fonts/FontLoader.h
@@ -1,29 +1,35 @@
#pragma once

#include "ifonts.h"

#include "ifilesystem.h"
#include "ThreadedDefLoader.h"

namespace fonts
{

class FontManager;

class FontLoader
class FontLoader :
public util::ThreadedDefLoader<void>
{
private:
// The base path for the shaders (e.g. "materials/")
std::string _basePath;

// The manager for registering the fonts
FontManager& _manager;

std::size_t _numFonts;

public:
// Constructor. Set the base path of the search.
FontLoader(const std::string& path, FontManager& manager) :
_basePath(path),
_manager(manager)
FontLoader(const std::string& path, const std::string& extension, FontManager& manager) :
ThreadedDefLoader(path, extension, 2, std::bind(&FontLoader::loadFonts, this)),
_manager(manager),
_numFonts(0)
{}

void operator()(const vfs::FileInfo& fileInfo);
private:
void loadFonts();
void loadFont(const vfs::FileInfo& fileInfo);
};

} // namespace fonts
75 changes: 37 additions & 38 deletions radiantcore/fonts/FontManager.cpp
Expand Up @@ -27,7 +27,6 @@ in game descriptor";
}

FontManager::FontManager() :
_loader(std::bind(&FontManager::loadFonts, this)),
_curLanguage("english")
{}

Expand All @@ -39,15 +38,13 @@ const std::string& FontManager::getName() const

const StringSet& FontManager::getDependencies() const
{
static StringSet _dependencies;

if (_dependencies.empty())
{
_dependencies.insert(MODULE_VIRTUALFILESYSTEM);
_dependencies.insert(MODULE_XMLREGISTRY);
_dependencies.insert(MODULE_GAMEMANAGER);
_dependencies.insert(MODULE_SHADERSYSTEM);
}
static StringSet _dependencies
{
MODULE_VIRTUALFILESYSTEM,
MODULE_XMLREGISTRY,
MODULE_GAMEMANAGER,
MODULE_SHADERSYSTEM,
};

return _dependencies;
}
Expand All @@ -56,13 +53,15 @@ void FontManager::initialiseModule(const IApplicationContext& ctx)
{
rMessage() << getName() << "::initialiseModule called" << std::endl;

_loader = std::make_unique<FontLoader>(getFontPath(), getFontExtension(), *this);

// Find installed fonts in a new thread
_loader.start();
_loader->start();
}

void FontManager::shutdownModule()
{
_loader.reset();
_loader->reset();
_fonts.clear();
}

Expand All @@ -73,45 +72,45 @@ const std::string& FontManager::getCurLanguage()

void FontManager::ensureFontsLoaded()
{
_loader.ensureFinished();
_loader->ensureFinished();
}

void FontManager::loadFonts()
std::size_t FontManager::getNumFonts()
{
_fonts.clear();

xml::NodeList nlBasePath = GlobalGameManager().currentGame()->getLocalXPath("/filesystem/fonts/basepath");

if (nlBasePath.empty())
{
throw xml::MissingXMLNodeException(MISSING_BASEPATH_NODE);
}
return _fonts.size();
}

xml::NodeList nlExt = GlobalGameManager().currentGame()->getLocalXPath("/filesystem/fonts/extension");
std::string FontManager::getFontPath()
{
auto nlBasePath = GlobalGameManager().currentGame()->getLocalXPath("/filesystem/fonts/basepath");

if (nlExt.empty())
{
throw xml::MissingXMLNodeException(MISSING_EXTENSION_NODE);
}
if (nlBasePath.empty())
{
throw xml::MissingXMLNodeException(MISSING_BASEPATH_NODE);
}

// TODO: Get the language from the registry
_curLanguage = "english";
// Load the DAT files from the VFS
return os::standardPathWithSlash(nlBasePath[0].getContent()) + _curLanguage + "/";
}

// Load the DAT files from the VFS
std::string path = os::standardPathWithSlash(nlBasePath[0].getContent()) + _curLanguage + "/";
std::string extension = nlExt[0].getContent();
std::string FontManager::getFontExtension()
{
auto nlExt = GlobalGameManager().currentGame()->getLocalXPath("/filesystem/fonts/extension");

// Instantiate a visitor to traverse the VFS
FontLoader loader(path, *this);
GlobalFileSystem().forEachFile(path, extension, loader, 2);
if (nlExt.empty())
{
throw xml::MissingXMLNodeException(MISSING_EXTENSION_NODE);
}

rMessage() << _fonts.size() << " fonts registered." << std::endl;
return nlExt[0].getContent();
}

void FontManager::reloadFonts()
{
_loader.reset();
_loader.start();
_fonts.clear();

_loader->reset();
_loader->start();
}

IFontInfoPtr FontManager::findFontInfo(const std::string& name)
Expand Down
14 changes: 9 additions & 5 deletions radiantcore/fonts/FontManager.h
Expand Up @@ -7,7 +7,7 @@
#include <map>

#include "FontInfo.h"
#include "ThreadedDefLoader.h"
#include "FontLoader.h"

namespace fonts
{
Expand All @@ -16,12 +16,12 @@ class FontManager :
public IFontManager
{
private:
std::string _curLanguage;

typedef std::map<std::string, FontInfoPtr> FontMap;
FontMap _fonts;

util::ThreadedDefLoader<void> _loader;

std::string _curLanguage;
std::unique_ptr<FontLoader> _loader;

public:
FontManager();
Expand All @@ -43,11 +43,15 @@ class FontManager :
// Returns the current language (e.g. "english")
const std::string& getCurLanguage();

std::size_t getNumFonts();

private:
void ensureFontsLoaded();

void loadFonts();
void reloadFonts();

std::string getFontPath();
std::string getFontExtension();
};
typedef std::shared_ptr<FontManager> FontManagerPtr;

Expand Down

0 comments on commit 689e06d

Please sign in to comment.