forked from mirrors/0ad
Makes loading terrain textures more smooth
This commit is contained in:
@@ -214,8 +214,12 @@ void CGameView::RegisterInit()
|
||||
|
||||
LDR_Register([](const double)
|
||||
{
|
||||
return g_TexMan.LoadTerrainTextures();
|
||||
}, L"LoadTerrainTextures", 60);
|
||||
return g_TexMan.StartTerrainTextures();
|
||||
}, L"StartTerrainTextures", 1);
|
||||
LDR_Register([](const double)
|
||||
{
|
||||
return g_TexMan.PollTerrainTextures();
|
||||
}, L"PollTerrainTextures", 60);
|
||||
}
|
||||
|
||||
void CGameView::BeginFrame()
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "lib/path.h"
|
||||
#include "lib/status.h"
|
||||
#include "lib/tex/tex.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/XMB/XMBStorage.h"
|
||||
@@ -121,10 +122,40 @@ static Status AddTextureCallback(const VfsPath& pathname, const CFileInfo&, cons
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
int CTerrainTextureManager::LoadTerrainTextures()
|
||||
struct CTerrainTextureManager::LoadTexturesState
|
||||
{
|
||||
AddTextureCallbackData data = {this, CTerrainPropertiesPtr(new CTerrainProperties(CTerrainPropertiesPtr()))};
|
||||
vfs::ForEachFile(g_VFS, L"art/terrains/", AddTextureCallback, (uintptr_t)&data, L"*.xml", vfs::DIR_RECURSIVE, AddTextureDirCallback, (uintptr_t)&data);
|
||||
vfs::ForEachFileContext context;
|
||||
AddTextureCallbackData data;
|
||||
|
||||
LoadTexturesState(const VfsPath& startPath, CTerrainTextureManager* self)
|
||||
: context{startPath}, data{self, std::make_shared<CTerrainProperties>(CTerrainPropertiesPtr())} {}
|
||||
};
|
||||
|
||||
int CTerrainTextureManager::StartTerrainTextures()
|
||||
{
|
||||
m_LoadTexturesState = std::make_unique<LoadTexturesState>(VfsPath{L"art/terrains/"}, this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CTerrainTextureManager::PollTerrainTextures()
|
||||
{
|
||||
LoadTexturesState& state{*m_LoadTexturesState};
|
||||
const size_t numberOfDirectoriesToLoadPerCall{10};
|
||||
for (size_t iteration{0}; !state.context.empty() && iteration < numberOfDirectoriesToLoadPerCall; ++iteration)
|
||||
{
|
||||
vfs::ForEachFileNext(state.context, g_VFS, AddTextureCallback, (uintptr_t)&state.data, L"*.xml", vfs::DIR_RECURSIVE, AddTextureDirCallback, (uintptr_t)&state.data);
|
||||
}
|
||||
|
||||
if (!state.context.empty())
|
||||
{
|
||||
// We don't know exact number so just using a rough approximation of the
|
||||
// current number.
|
||||
const size_t totalApproximateAmountOfTextures{1000};
|
||||
return Clamp<int>(m_TextureEntries.size() * 90 / totalApproximateAmountOfTextures, 10, 100);
|
||||
}
|
||||
|
||||
m_LoadTexturesState.reset();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,8 @@ public:
|
||||
|
||||
// Find all XML's in the directory (with subdirs) and try to load them as
|
||||
// terrain XML's
|
||||
int LoadTerrainTextures();
|
||||
int StartTerrainTextures();
|
||||
int PollTerrainTextures();
|
||||
|
||||
void UnloadTerrainTextures();
|
||||
|
||||
|
||||
@@ -60,40 +60,41 @@ Status GetPathnames(const PIVFS& fs, const VfsPath& path, const wchar_t* filter,
|
||||
|
||||
Status ForEachFile(const PIVFS& fs, const VfsPath& startPath, FileCallback cb, uintptr_t cbData, const wchar_t* pattern, size_t flags, DirCallback dircb, uintptr_t dircbData)
|
||||
{
|
||||
// (declare here to avoid reallocations)
|
||||
CFileInfos files;
|
||||
DirectoryNames subdirectoryNames;
|
||||
|
||||
// (a FIFO queue is more efficient than recursion because it uses less
|
||||
// stack space and avoids seeks due to breadth-first traversal.)
|
||||
std::queue<VfsPath> pendingDirectories;
|
||||
pendingDirectories.push(startPath/"");
|
||||
while(!pendingDirectories.empty())
|
||||
ForEachFileContext context{startPath};
|
||||
while(!context.pendingDirectories.empty())
|
||||
{
|
||||
const VfsPath& path = pendingDirectories.front();
|
||||
|
||||
RETURN_STATUS_IF_ERR(fs->GetDirectoryEntries(path, &files, &subdirectoryNames));
|
||||
|
||||
if(dircb)
|
||||
RETURN_STATUS_IF_ERR(dircb(path, dircbData));
|
||||
|
||||
for(size_t i = 0; i < files.size(); i++)
|
||||
{
|
||||
const CFileInfo fileInfo = files[i];
|
||||
if(!match_wildcard(fileInfo.Name().string().c_str(), pattern))
|
||||
continue;
|
||||
|
||||
const VfsPath pathname(path / fileInfo.Name()); // (CFileInfo only stores the name)
|
||||
RETURN_STATUS_IF_ERR(cb(pathname, fileInfo, cbData));
|
||||
}
|
||||
|
||||
if(!(flags & DIR_RECURSIVE))
|
||||
break;
|
||||
|
||||
for(size_t i = 0; i < subdirectoryNames.size(); i++)
|
||||
pendingDirectories.push(path / subdirectoryNames[i]/"");
|
||||
pendingDirectories.pop();
|
||||
RETURN_STATUS_IF_ERR(ForEachFileNext(context, fs, cb, cbData, pattern, flags, dircb, dircbData));
|
||||
}
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
Status ForEachFileNext(
|
||||
ForEachFileContext& context, const PIVFS& fs, FileCallback cb,
|
||||
uintptr_t cbData, const wchar_t* pattern, size_t flags,
|
||||
DirCallback dircb, uintptr_t dircbData)
|
||||
{
|
||||
const VfsPath path{std::move(context.pendingDirectories.front())};
|
||||
context.pendingDirectories.pop();
|
||||
|
||||
RETURN_STATUS_IF_ERR(fs->GetDirectoryEntries(path, &context.files, &context.subdirectoryNames));
|
||||
|
||||
if(dircb)
|
||||
RETURN_STATUS_IF_ERR(dircb(path, dircbData));
|
||||
|
||||
for (const CFileInfo& fileInfo : context.files)
|
||||
{
|
||||
if(!match_wildcard(fileInfo.Name().string().c_str(), pattern))
|
||||
continue;
|
||||
|
||||
const VfsPath pathname(path / fileInfo.Name()); // (CFileInfo only stores the name)
|
||||
RETURN_STATUS_IF_ERR(cb(pathname, fileInfo, cbData));
|
||||
}
|
||||
|
||||
if(!(flags & DIR_RECURSIVE))
|
||||
return INFO::OK;
|
||||
|
||||
for(const OsPath& subdirectoryName : context.subdirectoryNames)
|
||||
context.pendingDirectories.push(path / subdirectoryName / "");
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,10 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <queue>
|
||||
|
||||
namespace vfs {
|
||||
namespace vfs
|
||||
{
|
||||
|
||||
extern Status GetPathnames(const PIVFS& fs, const VfsPath& path, const wchar_t* filter, VfsPaths& pathnames);
|
||||
|
||||
@@ -84,8 +86,24 @@ enum DirFlags
|
||||
* @param dircbData
|
||||
* @return Status
|
||||
**/
|
||||
extern Status ForEachFile(const PIVFS& fs, const VfsPath& path, FileCallback cb, uintptr_t cbData, const wchar_t* pattern = 0, size_t flags = 0, DirCallback dircb = NULL, uintptr_t dircbData = 0);
|
||||
Status ForEachFile(const PIVFS& fs, const VfsPath& path, FileCallback cb, uintptr_t cbData, const wchar_t* pattern = 0, size_t flags = 0, DirCallback dircb = NULL, uintptr_t dircbData = 0);
|
||||
|
||||
struct ForEachFileContext
|
||||
{
|
||||
// (declare here to avoid reallocations)
|
||||
CFileInfos files;
|
||||
DirectoryNames subdirectoryNames;
|
||||
|
||||
// (a FIFO queue is more efficient than recursion because it uses less
|
||||
// stack space and avoids seeks due to breadth-first traversal.)
|
||||
std::queue<VfsPath> pendingDirectories;
|
||||
|
||||
ForEachFileContext(const VfsPath& startPath) { pendingDirectories.push(startPath / ""); }
|
||||
|
||||
bool empty() const { return pendingDirectories.empty(); }
|
||||
};
|
||||
// The same ForEachFile but allows to pause the iteration.
|
||||
Status ForEachFileNext(ForEachFileContext& context, const PIVFS& fs, FileCallback cb, uintptr_t cbData, const wchar_t* pattern = 0, size_t flags = 0, DirCallback dircb = NULL, uintptr_t dircbData = 0);
|
||||
|
||||
/**
|
||||
* Determine the next available pathname with a given format.
|
||||
@@ -100,7 +118,7 @@ extern Status ForEachFile(const PIVFS& fs, const VfsPath& path, FileCallback cb,
|
||||
* If 0, numbers corresponding to existing files are skipped.
|
||||
* @param nextPathname receives the output.
|
||||
**/
|
||||
extern void NextNumberedFilename(const PIVFS& fs, const VfsPath& pathnameFormat, size_t& nextNumber, VfsPath& nextPathname);
|
||||
void NextNumberedFilename(const PIVFS& fs, const VfsPath& pathnameFormat, size_t& nextNumber, VfsPath& nextPathname);
|
||||
|
||||
} // namespace vfs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user