mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-13 23:20:48 -06:00
Work on asset management
This commit is contained in:
@@ -617,6 +617,8 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) {
|
||||
}
|
||||
}
|
||||
|
||||
_assetLoader->synchronizeEnabledAssets();
|
||||
|
||||
_renderEngine->setGlobalBlackOutFactor(0.0);
|
||||
_renderEngine->startFading(1, 3.0);
|
||||
|
||||
|
||||
@@ -31,22 +31,25 @@
|
||||
|
||||
namespace {
|
||||
const char* _loggerCat = "Asset";
|
||||
|
||||
bool isRelative(std::string path) {
|
||||
if (path.size() > 2) {
|
||||
if (path[0] == '.' && path[1] == '/') return true;
|
||||
}
|
||||
if (path.size() > 3) {
|
||||
if (path[0] == '.' && path[1] == '.' && path[2] == '/') return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const char* AssetFileSuffix = "asset";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
|
||||
Asset::Asset(AssetLoader* loader)
|
||||
//: PropertyOwner({ "RootAsset", "Root asset" })
|
||||
: _readyState(Asset::ReadyState::Loaded)
|
||||
, _loader(loader)
|
||||
, _assetName("Root Asset")
|
||||
|
||||
{}
|
||||
|
||||
Asset::Asset(AssetLoader* loader, ghoul::filesystem::File assetPath)
|
||||
//: PropertyOwner({ assetPath, assetPath })
|
||||
: _readyState(Asset::ReadyState::Loaded)
|
||||
, _loader(loader)
|
||||
, _assetPath(assetPath)
|
||||
{}
|
||||
|
||||
std::string Asset::resolveLocalResource(std::string resourceName) {
|
||||
std::string currentAssetDirectory = assetDirectory();
|
||||
return currentAssetDirectory + ghoul::filesystem::FileSystem::PathSeparator + resourceName;
|
||||
@@ -54,7 +57,7 @@ std::string Asset::resolveLocalResource(std::string resourceName) {
|
||||
|
||||
std::string Asset::syncDirectory() const {
|
||||
std::string currentAssetDirectory = assetDirectory();
|
||||
std::string rootAssetDirectory = loader()->rootAsset()->assetDirectory();
|
||||
std::string rootAssetDirectory = loader()->syncRootDirectory();
|
||||
std::string relativePath = FileSys.relativePath(currentAssetDirectory, rootAssetDirectory);
|
||||
|
||||
return loader()->syncRootDirectory() +
|
||||
@@ -82,6 +85,36 @@ bool Asset::isInitReady() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Asset::synchronizeEnabledRecursive() {
|
||||
synchronize();
|
||||
for (Asset* a : _dependencies) {
|
||||
a->synchronizeEnabledRecursive();
|
||||
}
|
||||
for (Optional& o : _optionals) {
|
||||
if (o.second) {
|
||||
o.first->synchronizeEnabledRecursive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Asset::synchronize() {
|
||||
LDEBUG("Synchronizing asset " << id());
|
||||
|
||||
if (_readyState != Asset::ReadyState::Loaded) {
|
||||
// Already synchronized or synchronizing
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize dependencies
|
||||
for (auto& dependency : _dependencies) {
|
||||
dependency->synchronize();
|
||||
}
|
||||
|
||||
loader()->callOnSynchronize(this);
|
||||
|
||||
}
|
||||
|
||||
void Asset::initialize() {
|
||||
LDEBUG("Initializing asset " << id());
|
||||
if (_readyState == Asset::ReadyState::Initialized) {
|
||||
@@ -90,6 +123,7 @@ void Asset::initialize() {
|
||||
|
||||
if (!isInitReady()) {
|
||||
// TODO: THROW
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize dependencies
|
||||
@@ -137,65 +171,27 @@ std::string Asset::resolveSyncedResource(std::string resourceName) {
|
||||
resourceName;
|
||||
}
|
||||
|
||||
Asset::Asset(AssetLoader* loader, ghoul::filesystem::Directory directory)
|
||||
//: PropertyOwner({ "RootAsset", "Root asset" })
|
||||
: _assetDirectory(directory)
|
||||
, _loader(loader)
|
||||
, _readyState(Asset::ReadyState::Loaded)
|
||||
{
|
||||
_id = generateAssetId(directory, "");
|
||||
}
|
||||
|
||||
Asset::Asset(AssetLoader* loader, ghoul::filesystem::Directory baseDirectory, std::string assetPath)
|
||||
//: PropertyOwner({ assetPath, assetPath })
|
||||
: _readyState(Asset::ReadyState::Loaded)
|
||||
, _loader(loader)
|
||||
{
|
||||
if (isRelative(assetPath)) {
|
||||
ghoul::filesystem::File assetFile =
|
||||
static_cast<std::string>(baseDirectory) +
|
||||
ghoul::filesystem::FileSystem::PathSeparator +
|
||||
assetPath +
|
||||
"." +
|
||||
AssetFileSuffix;
|
||||
|
||||
_assetDirectory = assetFile.directoryName();
|
||||
_assetName = assetFile.baseName();
|
||||
} else {
|
||||
std::string assetRoot = ghoul::filesystem::Directory(loader->rootAsset()->assetDirectory());
|
||||
ghoul::filesystem::File assetFile =
|
||||
assetRoot +
|
||||
ghoul::filesystem::FileSystem::PathSeparator +
|
||||
assetPath +
|
||||
"." +
|
||||
AssetFileSuffix;
|
||||
|
||||
_assetDirectory = assetFile.directoryName();
|
||||
_assetName = assetFile.baseName();
|
||||
}
|
||||
_id = generateAssetId(_assetDirectory, _assetName);
|
||||
std::string Asset::id() const {
|
||||
return _assetPath.has_value() ? _assetPath.value() : "";
|
||||
}
|
||||
|
||||
std::string Asset::assetFilePath() const {
|
||||
//ghoul::filesystem::File dir(_assetDirectory);
|
||||
return _assetDirectory + ghoul::filesystem::FileSystem::PathSeparator + _assetName + "." + AssetFileSuffix;
|
||||
return _assetPath.value();
|
||||
}
|
||||
|
||||
std::string Asset::generateAssetId(std::string directory, std::string name) {
|
||||
return directory + ghoul::filesystem::FileSystem::PathSeparator + name;
|
||||
bool Asset::hasAssetFile() const {
|
||||
return _assetPath.has_value();
|
||||
}
|
||||
|
||||
std::string Asset::assetDirectory() const {
|
||||
return ghoul::filesystem::File(_assetPath.value()).directoryName();
|
||||
}
|
||||
|
||||
std::string Asset::assetName() const {
|
||||
return _assetName;
|
||||
}
|
||||
|
||||
std::string Asset::assetDirectory() const {
|
||||
return _assetDirectory;
|
||||
}
|
||||
|
||||
std::string Asset::id() const {
|
||||
return _id;
|
||||
}
|
||||
|
||||
AssetLoader* Asset::loader() const {
|
||||
return _loader;
|
||||
|
||||
@@ -45,6 +45,9 @@ namespace {
|
||||
|
||||
const char* SyncedResourceFunctionName = "syncedResource";
|
||||
const char* LocalResourceFunctionName = "localResource";
|
||||
|
||||
const char* OnSynchronizeFunctionName = "onSynchronize";
|
||||
|
||||
const char* OnInitializeFunctionName = "onInitialize";
|
||||
const char* OnDeinitializeFunctionName = "onDeinitialize";
|
||||
|
||||
@@ -52,6 +55,18 @@ namespace {
|
||||
const char* DependantsTableName = "_dependants";
|
||||
|
||||
const char* _loggerCat = "AssetLoader";
|
||||
|
||||
const char* AssetFileSuffix = "asset";
|
||||
|
||||
bool isRelative(std::string path) {
|
||||
if (path.size() > 2) {
|
||||
if (path[0] == '.' && path[1] == '/') return true;
|
||||
}
|
||||
if (path.size() > 3) {
|
||||
if (path[0] == '.' && path[1] == '.' && path[2] == '/') return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
@@ -118,20 +133,34 @@ int resolveSyncedResource(lua_State* state) {
|
||||
return asset->loader()->resolveSyncedResourceLua(asset);
|
||||
}
|
||||
|
||||
int onFinishSynchronization(lua_State* state) {
|
||||
Asset* asset =
|
||||
reinterpret_cast<Asset*>(lua_touserdata(state, lua_upvalueindex(1)));
|
||||
return asset->loader()->onFinishSynchronizationLua(asset);
|
||||
}
|
||||
|
||||
int noOperation(lua_State* state) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int noSynchronization(lua_State* state) {
|
||||
|
||||
int nArguments = lua_gettop(state);
|
||||
// Todo: call onFinish.
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace assetloader
|
||||
|
||||
AssetLoader::AssetLoader(
|
||||
ghoul::lua::LuaState& luaState,
|
||||
ResourceSynchronizer& resourceSynchronizer,
|
||||
std::string assetRoot,
|
||||
std::string assetRootDirectory,
|
||||
std::string syncRootDirectory
|
||||
)
|
||||
: _luaState(&luaState)
|
||||
, _rootAsset(std::make_unique<Asset>(this, std::move(assetRoot)))
|
||||
, _rootAsset(std::make_unique<Asset>(this))
|
||||
, _assetRootDirectory(assetRootDirectory)
|
||||
, _syncRootDirectory(std::move(syncRootDirectory))
|
||||
, _resourceSynchronizer(&resourceSynchronizer)
|
||||
{
|
||||
@@ -142,9 +171,8 @@ AssetLoader::AssetLoader(
|
||||
lua_setglobal(*_luaState, AssetsTableName);
|
||||
}
|
||||
|
||||
Asset* AssetLoader::loadAsset(std::string name) {
|
||||
ghoul::filesystem::Directory directory = currentDirectory();
|
||||
std::unique_ptr<Asset> asset = std::make_unique<Asset>(this, directory, name);
|
||||
Asset* AssetLoader::loadAsset(std::string path) {
|
||||
std::unique_ptr<Asset> asset = std::make_unique<Asset>(this, path);
|
||||
|
||||
Asset* rawAsset = asset.get();
|
||||
|
||||
@@ -153,7 +181,6 @@ Asset* AssetLoader::loadAsset(std::string name) {
|
||||
popAsset();
|
||||
});
|
||||
|
||||
const std::string path = asset->assetFilePath();
|
||||
if (!FileSys.fileExists(path)) {
|
||||
throw ghoul::FileNotFoundError(path);
|
||||
}
|
||||
@@ -175,19 +202,48 @@ Asset* AssetLoader::loadAsset(std::string name) {
|
||||
return rawAsset;
|
||||
}
|
||||
|
||||
std::string AssetLoader::generateAssetPath(const std::string& baseDirectory, const std::string& assetPath) const {
|
||||
if (isRelative(assetPath)) {
|
||||
ghoul::filesystem::File assetFile =
|
||||
static_cast<std::string>(baseDirectory) +
|
||||
ghoul::filesystem::FileSystem::PathSeparator +
|
||||
assetPath +
|
||||
"." +
|
||||
AssetFileSuffix;
|
||||
|
||||
return assetFile.path();
|
||||
}
|
||||
else {
|
||||
std::string assetRoot = ghoul::filesystem::Directory(_assetRootDirectory);
|
||||
ghoul::filesystem::File assetFile =
|
||||
assetRoot +
|
||||
ghoul::filesystem::FileSystem::PathSeparator +
|
||||
assetPath +
|
||||
"." +
|
||||
AssetFileSuffix;
|
||||
|
||||
return assetFile.path();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Asset* AssetLoader::getAsset(std::string name) {
|
||||
ghoul::filesystem::Directory directory = currentDirectory();
|
||||
std::string assetId = Asset::generateAssetId(directory, name);
|
||||
std::string path = generateAssetPath(directory, name);
|
||||
|
||||
// Check if asset is already loaded.
|
||||
const auto it = _importedAssets.find(assetId);
|
||||
const auto it = _importedAssets.find(path);
|
||||
const bool loaded = it != _importedAssets.end();
|
||||
|
||||
return loaded ? it->second.get() : loadAsset(name);
|
||||
return loaded ? it->second.get() : loadAsset(path);
|
||||
}
|
||||
|
||||
Asset* AssetLoader::importDependency(const std::string& name) {
|
||||
Asset* asset = getAsset(name);
|
||||
if (!asset) {
|
||||
// TODO: Throw
|
||||
return nullptr;
|
||||
}
|
||||
Asset* dependant = _assetStack.back();
|
||||
dependant->addDependency(asset);
|
||||
return asset;
|
||||
@@ -195,13 +251,25 @@ Asset* AssetLoader::importDependency(const std::string& name) {
|
||||
|
||||
Asset* AssetLoader::importOptional(const std::string& name, bool enabled) {
|
||||
Asset* asset = getAsset(name);
|
||||
if (!asset) {
|
||||
// TODO: Throw
|
||||
return nullptr;
|
||||
}
|
||||
Asset* owner = _assetStack.back();
|
||||
owner->addOptional(asset, enabled);
|
||||
return asset;
|
||||
}
|
||||
|
||||
ghoul::filesystem::Directory AssetLoader::currentDirectory() {
|
||||
return _assetStack.back()->assetDirectory();
|
||||
if (_assetStack.back()->hasAssetFile()) {
|
||||
return _assetStack.back()->assetDirectory();
|
||||
} else {
|
||||
return _assetRootDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
void AssetLoader::synchronizeEnabledAssets() {
|
||||
_rootAsset->synchronizeEnabledRecursive();
|
||||
}
|
||||
|
||||
void AssetLoader::loadSingleAsset(const std::string& identifier) {
|
||||
@@ -219,7 +287,7 @@ void AssetLoader::loadSingleAsset(const std::string& identifier) {
|
||||
void AssetLoader::importAsset(const std::string & identifier) {
|
||||
ghoul_assert(_assetStack.size() == 1, "Can only import an asset from the root asset");
|
||||
try {
|
||||
importAsset(identifier);
|
||||
importOptional(identifier);
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERROR("Error loading asset '" << identifier << "': " << e.message);
|
||||
@@ -231,11 +299,7 @@ void AssetLoader::unimportAsset(const std::string & identifier) {
|
||||
ghoul_assert(_assetStack.size() == 1, "Can only unimport an asset from the root asset");
|
||||
|
||||
ghoul::filesystem::Directory directory = currentDirectory();
|
||||
Asset tempAsset(this, directory, identifier);
|
||||
const std::string id = tempAsset.id();
|
||||
|
||||
_rootAsset->removeDependency(id);
|
||||
|
||||
//_rootAsset->removeOptional(id);
|
||||
}
|
||||
|
||||
|
||||
@@ -251,6 +315,25 @@ const std::string& AssetLoader::syncRootDirectory() {
|
||||
return _syncRootDirectory;
|
||||
}
|
||||
|
||||
void AssetLoader::callOnSynchronize(Asset* asset) {
|
||||
if (asset == _rootAsset.get()) {
|
||||
return;
|
||||
}
|
||||
lua_getglobal(*_luaState, AssetsTableName);
|
||||
lua_getfield(*_luaState, -1, asset->id().c_str());
|
||||
lua_getfield(*_luaState, -1, OnSynchronizeFunctionName);
|
||||
|
||||
// onSynchronize(function<void(bool)> onFinish)
|
||||
|
||||
lua_pushlightuserdata(*_luaState, asset);
|
||||
lua_pushcclosure(*_luaState, &assetloader::onFinishSynchronization, 1);
|
||||
|
||||
const int status = lua_pcall(*_luaState, 1, 0, 0);
|
||||
if (status != LUA_OK) {
|
||||
throw ghoul::lua::LuaExecutionException(lua_tostring(*_luaState, -1));
|
||||
}
|
||||
}
|
||||
|
||||
void AssetLoader::callOnInitialize(Asset * asset) {
|
||||
if (asset == _rootAsset.get()) {
|
||||
return;
|
||||
@@ -308,6 +391,10 @@ void AssetLoader::callOnDependantDeinitialize(Asset* asset, Asset* dependant) {
|
||||
}
|
||||
}
|
||||
|
||||
void AssetLoader::synchronizeResource(const ghoul::Dictionary & d, std::function<void(bool)> onFinish) {
|
||||
onFinish(true);
|
||||
}
|
||||
|
||||
|
||||
int AssetLoader::resolveLocalResourceLua(Asset* asset) {
|
||||
int nArguments = lua_gettop(*_luaState);
|
||||
@@ -335,6 +422,11 @@ int AssetLoader::resolveSyncedResourceLua(Asset* asset) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int AssetLoader::onFinishSynchronizationLua(Asset* asset) {
|
||||
LINFO("Finished syncing resource!" << asset->id());
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AssetLoader::pushAsset(Asset* asset) {
|
||||
_assetStack.push_back(asset);
|
||||
|
||||
@@ -370,7 +462,12 @@ void AssetLoader::pushAsset(Asset* asset) {
|
||||
lua_pushcclosure(*_luaState, &assetloader::importOptional, 1);
|
||||
lua_setfield(*_luaState, assetTableIndex, ImportOptionalFunctionName);
|
||||
|
||||
// Register default onDeinitialize function
|
||||
// Register default onSynchronize function
|
||||
lua_pushlightuserdata(*_luaState, this);
|
||||
lua_pushcclosure(*_luaState, &assetloader::noSynchronization, 1);
|
||||
lua_setfield(*_luaState, assetTableIndex, OnSynchronizeFunctionName);
|
||||
|
||||
// Register default onInitialize function
|
||||
lua_pushcfunction(*_luaState, &assetloader::noOperation);
|
||||
lua_setfield(*_luaState, assetTableIndex, OnInitializeFunctionName);
|
||||
|
||||
@@ -483,6 +580,13 @@ scripting::LuaLibrary AssetLoader::luaLibrary() {
|
||||
"string",
|
||||
""
|
||||
},
|
||||
{
|
||||
"synchronizeResource",
|
||||
&luascriptfunctions::synchronizeResource,
|
||||
{ this },
|
||||
"table, function",
|
||||
""
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
|
||||
namespace openspace {
|
||||
namespace luascriptfunctions {
|
||||
|
||||
@@ -52,5 +51,33 @@ int unimportAsset(lua_State* state) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int synchronizeResource(lua_State* state) {
|
||||
AssetLoader *assetLoader =
|
||||
reinterpret_cast<AssetLoader*>(lua_touserdata(state, lua_upvalueindex(1)));
|
||||
|
||||
int nArguments = lua_gettop(state);
|
||||
SCRIPT_CHECK_ARGUMENTS("addSynchronization", state, 2, nArguments);
|
||||
|
||||
int referenceIndex = luaL_ref(state, LUA_REGISTRYINDEX);
|
||||
|
||||
ghoul::Dictionary d;
|
||||
try {
|
||||
ghoul::lua::luaDictionaryFromState(state, d);
|
||||
}
|
||||
catch (const ghoul::lua::LuaFormatException& e) {
|
||||
LERRORC("addSceneGraphNode", e.what());
|
||||
return luaL_error(state, "Error loading dictionary from lua state");
|
||||
}
|
||||
|
||||
|
||||
assetLoader->synchronizeResource(d, [state, referenceIndex](bool success) {
|
||||
lua_rawgeti(state, LUA_REGISTRYINDEX, referenceIndex);
|
||||
lua_pushboolean(state, success ? 1 : 0);
|
||||
lua_pcall(state, 1, 0, 0);
|
||||
luaL_unref(state, LUA_REGISTRYINDEX, referenceIndex);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user