Use shared pointers for assets

This commit is contained in:
Emil Axelsson
2017-10-19 15:48:07 +02:00
parent 27dea20520
commit 9e5a033cd2
8 changed files with 197 additions and 118 deletions

View File

@@ -47,6 +47,7 @@
#include <openspace/scene/asset.h>
#include <openspace/scene/assetloader.h>
#include <openspace/scene/assetsynchronizer.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/rotation.h>
#include <openspace/scene/scale.h>
@@ -146,6 +147,7 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName,
, _parallelConnection(new ParallelConnection)
, _renderEngine(new RenderEngine)
, _resourceSynchronizer(new ResourceSynchronizer)
, _assetSynchronizer(new AssetSynchronizer(_resourceSynchronizer.get()))
, _settingsEngine(new SettingsEngine)
, _syncEngine(std::make_unique<SyncEngine>(4096))
, _timeManager(new TimeManager)
@@ -595,7 +597,15 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) {
_scene = std::make_unique<Scene>();
_renderEngine->setScene(_scene.get());
_assetLoader->loadSingleAsset(assetPath);
std::shared_ptr<Asset> asset = _assetLoader->loadSingleAsset(assetPath);
std::vector<std::shared_ptr<Asset>> assets = asset->allActiveAssets();
for (const auto& asset : assets) {
_assetSynchronizer->addAsset(asset);
}
LINFO("SYNCS");
asset->initialize();
} catch (const ghoul::FileNotFoundError& e) {
LERRORC(e.component, e.message);
return;
@@ -1481,6 +1491,11 @@ ResourceSynchronizer & OpenSpaceEngine::resourceSynchronizer() {
return *_resourceSynchronizer;
}
AssetSynchronizer & OpenSpaceEngine::assetSynchronizer() {
ghoul_assert(_assetSynchronizer, "Asset Synchronizer must not be nullptr");
return *_assetSynchronizer;
}
ghoul::fontrendering::FontManager& OpenSpaceEngine::fontManager() {
ghoul_assert(_fontManager, "Font Manager must not be nullptr");
return *_fontManager;

View File

@@ -59,7 +59,7 @@ std::string Asset::resolveLocalResource(std::string resourceName) {
std::string Asset::syncDirectory() const {
std::string currentAssetDirectory = assetDirectory();
std::string rootAssetDirectory = loader()->syncRootDirectory();
std::string rootAssetDirectory = loader()->assetRootDirectory();
std::string relativePath = FileSys.relativePath(currentAssetDirectory,
rootAssetDirectory);
@@ -67,7 +67,7 @@ std::string Asset::syncDirectory() const {
ghoul::filesystem::FileSystem::PathSeparator +
relativePath +
ghoul::filesystem::FileSystem::PathSeparator +
assetName();
ghoul::filesystem::File(_assetPath.value()).baseName();
}
Asset::ReadyState Asset::readyState() const {
@@ -78,6 +78,41 @@ void Asset::addSynchronization(std::shared_ptr<ResourceSynchronization> synchron
_synchronizations.push_back(synchronization);
}
std::vector<std::shared_ptr<ResourceSynchronization>> Asset::synchronizations()
{
return _synchronizations;
}
std::vector<std::shared_ptr<Asset>> Asset::allAssets() {
std::set<std::shared_ptr<Asset>> assets({ shared_from_this() });
for (auto& dep : _requiredDependencies) {
std::vector<std::shared_ptr<Asset>> depAssets = dep->allActiveAssets();
std::copy(depAssets.begin(), depAssets.end(), std::inserter(assets, assets.end()));
}
for (auto& dep : _optionalDependencies) {
std::vector<std::shared_ptr<Asset>> depAssets = dep.first->allActiveAssets();
std::copy(depAssets.begin(), depAssets.end(), std::inserter(assets, assets.end()));
}
std::vector<std::shared_ptr<Asset>> assetVector(assets.begin(), assets.end());
return assetVector;
}
std::vector<std::shared_ptr<Asset >> Asset::allActiveAssets() {
std::set<std::shared_ptr<Asset>> assets({ shared_from_this() });
for (auto& dep : _requiredDependencies) {
std::vector<std::shared_ptr<Asset>> depAssets = dep->allActiveAssets();
std::copy(depAssets.begin(), depAssets.end(), std::inserter(assets, assets.end()));
}
for (auto& dep : _optionalDependencies) {
if (dep.second) {
std::vector<std::shared_ptr<Asset>> depAssets = dep.first->allActiveAssets();
std::copy(depAssets.begin(), depAssets.end(), std::inserter(assets, assets.end()));
}
}
std::vector<std::shared_ptr<Asset>> assetVector(assets.begin(), assets.end());
return assetVector;
}
bool Asset::isInitReady() const {
// An asset is ready for initialization if all synchronizations are resolved
// and all its required dependencies are ready for initialization.
@@ -117,7 +152,7 @@ void Asset::initialize() {
// Notify dependencies
for (auto& dependency : _requiredDependencies) {
dependency->dependantDidInitialize(this);
loader()->callOnDependantInitialize(dependency.get(), this);
}
}
@@ -128,7 +163,7 @@ void Asset::deinitialize() {
// Notify dependencies
for (auto& dependency : _requiredDependencies) {
dependency->dependantWillDeinitialize(this);
loader()->callOnDependantDeinitialize(dependency.get(), this);
}
// Call onDeinitialize in Lua
@@ -170,21 +205,23 @@ std::string Asset::assetName() const {
return _assetName;
}
AssetLoader* Asset::loader() const {
return _loader;
}
bool Asset::hasRequiredDependency(const Asset* asset) const {
const auto it = std::find(_requiredDependencies.begin(),
_requiredDependencies.end(),
asset);
const auto it = std::find_if(
_requiredDependencies.begin(),
_requiredDependencies.end(),
[asset](std::shared_ptr<Asset> dep) {
return dep.get() == asset;
}
);
return it != _requiredDependencies.end();
}
void Asset::addRequiredDependency(Asset* dependency) {
void Asset::addRequiredDependency(std::shared_ptr<Asset> dependency) {
if (_readyState == Asset::ReadyState::Initialized) {
// TODO: Throw: cannot add dep while asset is initialized.
return;
@@ -200,22 +237,26 @@ void Asset::addRequiredDependency(Asset* dependency) {
}
_requiredDependencies.push_back(dependency);
dependency->_requiredDependants.push_back(this);
dependency->_requiredDependants.push_back(shared_from_this());
//addPropertySubOwner(dependency);
}
void Asset::removeRequiredDependency(Asset* dependency) {
_requiredDependencies.erase(
std::remove(_requiredDependencies.begin(),
std::remove_if(_requiredDependencies.begin(),
_requiredDependencies.end(),
dependency),
[dependency](std::shared_ptr<Asset> asset) {
return asset.get() == dependency;
}
),
_requiredDependencies.end()
);
std::vector<Asset*>& dependants = dependency->_requiredDependants;
std::vector<std::weak_ptr<Asset>>& dependants = dependency->_requiredDependants;
dependants.erase(
std::remove(dependants.begin(), dependants.end(), this),
std::remove_if(dependants.begin(), dependants.end(), [this](std::weak_ptr<Asset> asset) {
return asset.lock().get() == this;
}),
dependants.end()
);
@@ -228,33 +269,27 @@ void Asset::removeRequiredDependency(const std::string& assetId) {
auto dep = std::find_if(
_requiredDependencies.begin(),
_requiredDependencies.end(),
[&assetId](const Asset* d) {
[&assetId](const std::shared_ptr<Asset>& d) {
return d->id() == assetId;
});
if (dep != _requiredDependencies.end()) {
removeRequiredDependency(*dep);
removeRequiredDependency(dep->get());
} else {
LERROR("No such dependency '" << assetId << "'");
}
}
void Asset::dependantDidInitialize(Asset* dependant) {
loader()->callOnDependantInitialize(this, dependant);
}
void Asset::dependantWillDeinitialize(Asset* dependant) {
loader()->callOnDependantDeinitialize(this, dependant);
}
bool Asset::hasDependants() const {
for (const auto& dependant : _requiredDependants) {
if (dependant->hasRequiredDependency(this)) {
std::shared_ptr<Asset> d = dependant.lock();
if (d && d->hasRequiredDependency(this)) {
return true;
}
}
for (const auto& dependant : _optionalDependants) {
if (dependant->hasEnabledOptionalDependency(this)) {
std::shared_ptr<Asset> d = dependant.lock();
if (d && d->hasEnabledOptionalDependency(this)) {
return true;
}
}
@@ -263,15 +298,17 @@ bool Asset::hasDependants() const {
bool Asset::hasInitializedDependants() const {
for (const auto& dependant : _requiredDependants) {
if (dependant->readyState() == Asset::ReadyState::Initialized &&
dependant->hasRequiredDependency(this))
std::shared_ptr<Asset> d = dependant.lock();
if (d && d->readyState() == Asset::ReadyState::Initialized &&
d->hasRequiredDependency(this))
{
return true;
}
}
for (const auto& dependant : _optionalDependants) {
if (dependant->readyState() == Asset::ReadyState::Initialized &&
dependant->hasEnabledOptionalDependency(this))
std::shared_ptr<Asset> d = dependant.lock();
if (d && d->readyState() == Asset::ReadyState::Initialized &&
d->hasEnabledOptionalDependency(this))
{
return true;
}
@@ -279,8 +316,8 @@ bool Asset::hasInitializedDependants() const {
return false;
}
std::vector<Asset*> Asset::optionalAssets() const {
std::vector<Asset*> assets(_optionalDependencies.size());
std::vector<std::shared_ptr<Asset>> Asset::optionalAssets() const {
std::vector<std::shared_ptr<Asset>> assets(_optionalDependencies.size());
std::transform(
_optionalDependencies.begin(),
_optionalDependencies.end(),
@@ -297,7 +334,7 @@ bool Asset::hasOptionalDependency(const Asset* asset) const {
_optionalDependencies.begin(),
_optionalDependencies.end(),
[&asset](const Optional& o) {
return o.first == asset;
return o.first.get() == asset;
}
);
return it != _optionalDependencies.end();
@@ -308,7 +345,7 @@ bool Asset::hasEnabledOptionalDependency(const Asset* asset) const {
_optionalDependencies.begin(),
_optionalDependencies.end(),
[&asset](const Optional& o) {
return o.first == asset && o.second;
return o.first.get() == asset && o.second;
}
);
return it != _optionalDependencies.end();
@@ -319,7 +356,7 @@ void Asset::setOptionalDependencyEnabled(Asset* asset, bool enabled) {
_optionalDependencies.begin(),
_optionalDependencies.end(),
[&asset](const Optional& o) {
return o.first == asset;
return o.first.get() == asset;
}
);
@@ -334,7 +371,7 @@ void Asset::removeOptionalDependency(Asset* asset) {
_optionalDependencies.begin(),
_optionalDependencies.end(),
[&asset](Optional& o) {
return o.first == asset;
return o.first.get() == asset;
}
),
_optionalDependencies.end()
@@ -342,7 +379,7 @@ void Asset::removeOptionalDependency(Asset* asset) {
// TODO: Update and validate
}
void Asset::addOptionalDependency(Asset* asset, bool enabled) {
void Asset::addOptionalDependency(std::shared_ptr<Asset> asset, bool enabled) {
_optionalDependencies.push_back(std::make_pair(asset, enabled));
// TODO: Update and validate
}

View File

@@ -77,11 +77,11 @@ AssetLoader::AssetLoader(
std::string syncRootDirectory
)
: _luaState(&luaState)
, _rootAsset(std::make_unique<Asset>(this))
, _rootAsset(std::make_shared<Asset>(this))
, _assetRootDirectory(assetRootDirectory)
, _syncRootDirectory(std::move(syncRootDirectory))
{
pushAsset(_rootAsset.get());
pushAsset(_rootAsset);
// Create _assets table.
lua_newtable(*_luaState);
@@ -91,12 +91,10 @@ AssetLoader::AssetLoader(
AssetLoader::~AssetLoader() {
}
Asset* AssetLoader::loadAsset(std::string path) {
std::unique_ptr<Asset> asset = std::make_unique<Asset>(this, path);
std::shared_ptr<Asset> AssetLoader::loadAsset(std::string path) {
std::shared_ptr<Asset> asset = std::make_shared<Asset>(this, path);
Asset* rawAsset = asset.get();
pushAsset(rawAsset);
pushAsset(asset);
ghoul::OnScopeExit e([this]() {
popAsset();
});
@@ -106,9 +104,9 @@ Asset* AssetLoader::loadAsset(std::string path) {
}
ghoul::lua::runScriptFile(*_luaState, path);
_importedAssets.emplace(rawAsset->id(), std::move(asset));
_importedAssets.emplace(asset->id(), asset);
return rawAsset;
return asset;
}
std::string AssetLoader::generateAssetPath(const std::string& baseDirectory,
@@ -125,7 +123,7 @@ std::string AssetLoader::generateAssetPath(const std::string& baseDirectory,
AssetFileSuffix);
}
Asset* AssetLoader::getAsset(std::string name) {
std::shared_ptr<Asset> AssetLoader::getAsset(std::string name) {
ghoul::filesystem::Directory directory = currentDirectory();
std::string path = generateAssetPath(directory, name);
@@ -134,7 +132,7 @@ Asset* AssetLoader::getAsset(std::string name) {
return it == _importedAssets.end() ?
loadAsset(path) :
it->second.get();
it->second;
}
int AssetLoader::onInitializeLua(Asset* asset) {
@@ -180,16 +178,16 @@ int AssetLoader::addSynchronizationLua(Asset* asset) {
return 0;
}
Asset* AssetLoader::importRequiredDependency(const std::string& name) {
Asset* asset = getAsset(name);
Asset* dependant = _assetStack.back();
std::shared_ptr<Asset> AssetLoader::importRequiredDependency(const std::string& name) {
std::shared_ptr<Asset> asset = getAsset(name);
std::shared_ptr<Asset> dependant = _assetStack.back();
dependant->addRequiredDependency(asset);
return asset;
}
Asset* AssetLoader::importOptionalDependency(const std::string& name, bool enabled) {
Asset* asset = getAsset(name);
Asset* owner = _assetStack.back();
std::shared_ptr<Asset> AssetLoader::importOptionalDependency(const std::string& name, bool enabled) {
std::shared_ptr<Asset> asset = getAsset(name);
std::shared_ptr<Asset> owner = _assetStack.back();
owner->addOptionalDependency(asset, enabled);
return asset;
}
@@ -202,20 +200,20 @@ ghoul::filesystem::Directory AssetLoader::currentDirectory() {
}
}
Asset* AssetLoader::loadSingleAsset(const std::string& identifier) {
Asset* imported = importOptionalDependency(identifier, true);
std::vector<Asset*> optionals = _rootAsset->optionalAssets();
std::shared_ptr<Asset> AssetLoader::loadSingleAsset(const std::string& identifier) {
std::shared_ptr<Asset> imported = importOptionalDependency(identifier, true);
std::vector<std::shared_ptr<Asset>> optionals = _rootAsset->optionalAssets();
// Remove all other optionals
for (auto& optional : optionals) {
if (optional != imported) {
_rootAsset->removeOptionalDependency(optional);
_rootAsset->removeOptionalDependency(optional.get());
}
}
return imported;
}
Asset* AssetLoader::importAsset(const std::string & identifier) {
std::shared_ptr<Asset> AssetLoader::importAsset(const std::string & identifier) {
ghoul_assert(_assetStack.size() == 1, "Can only import an asset from the root asset");
return importOptionalDependency(identifier);
}
@@ -233,19 +231,26 @@ ghoul::lua::LuaState* AssetLoader::luaState() {
return _luaState;
}
Asset* AssetLoader::rootAsset() const {
return _rootAsset.get();
std::shared_ptr<Asset> AssetLoader::rootAsset() const {
return _rootAsset;
}
const std::string& AssetLoader::syncRootDirectory() {
return _syncRootDirectory;
}
const std::string & AssetLoader::assetRootDirectory()
{
return _assetRootDirectory;
}
void AssetLoader::callOnInitialize(Asset* asset) {
for (int init : _onInitializationFunctionRefs[asset]) {
lua_rawgeti(*_luaState, LUA_REGISTRYINDEX, init);
if (lua_pcall(*_luaState, 0, 0, 0) != LUA_OK) {
throw ghoul::lua::LuaRuntimeException(luaL_checkstring(*_luaState, -1));
throw ghoul::lua::LuaRuntimeException(
"When initializing " + asset->assetFilePath() + ": " + luaL_checkstring(*_luaState, -1)
);
}
}
}
@@ -255,7 +260,9 @@ void AssetLoader::callOnDeinitialize(Asset * asset) {
for (auto it = funs.rbegin(); it != funs.rend(); it++) {
lua_rawgeti(*_luaState, LUA_REGISTRYINDEX, *it);
if (lua_pcall(*_luaState, 0, 0, 0) != LUA_OK) {
throw ghoul::lua::LuaRuntimeException(luaL_checkstring(*_luaState, -1));
throw ghoul::lua::LuaRuntimeException(
"When deinitializing " + asset->assetFilePath() + ": " + luaL_checkstring(*_luaState, -1)
);
}
}
}
@@ -264,7 +271,10 @@ void AssetLoader::callOnDependantInitialize(Asset* asset, Asset* dependant) {
for (int init : _onDependencyInitializationFunctionRefs[dependant][asset]) {
lua_rawgeti(*_luaState, LUA_REGISTRYINDEX, init);
if (lua_pcall(*_luaState, 0, 0, 0) != LUA_OK) {
throw ghoul::lua::LuaRuntimeException(luaL_checkstring(*_luaState, -1));
throw ghoul::lua::LuaRuntimeException(
"When initializing dependency " + dependant->assetFilePath() + " -> " +
asset->assetFilePath() + ": " + luaL_checkstring(*_luaState, -1)
);
}
}
}
@@ -274,7 +284,10 @@ void AssetLoader::callOnDependantDeinitialize(Asset* asset, Asset* dependant) {
for (auto it = funs.rbegin(); it != funs.rend(); it++) {
lua_rawgeti(*_luaState, LUA_REGISTRYINDEX, *it);
if (lua_pcall(*_luaState, 0, 0, 0) != LUA_OK) {
throw ghoul::lua::LuaRuntimeException(luaL_checkstring(*_luaState, -1));
throw ghoul::lua::LuaRuntimeException(
"When deinitializing dependency " + dependant->assetFilePath() + " -> " +
asset->assetFilePath() + ": " + luaL_checkstring(*_luaState, -1)
);
}
}
}
@@ -305,10 +318,14 @@ int AssetLoader::resolveSyncedResourceLua(Asset* asset) {
return 1;
}
void AssetLoader::pushAsset(Asset* asset) {
void AssetLoader::pushAsset(std::shared_ptr<Asset> asset) {
if (std::find(_assetStack.begin(), _assetStack.end(), asset) != _assetStack.end()) {
throw ghoul::lua::LuaRuntimeException("Circular inclusion of assets.");
}
_assetStack.push_back(asset);
if (asset == _rootAsset.get()) {
if (asset == _rootAsset) {
return;
}
@@ -354,49 +371,49 @@ void AssetLoader::pushAsset(Asset* asset) {
// Register local resource function
// string localResource(string path)
lua_pushlightuserdata(*_luaState, asset);
lua_pushlightuserdata(*_luaState, asset.get());
lua_pushcclosure(*_luaState, &assetloader::resolveLocalResource, 1);
lua_setfield(*_luaState, assetTableIndex, LocalResourceFunctionName);
// Register synced resource function
// string syncedResource(string path)
lua_pushlightuserdata(*_luaState, asset);
lua_pushlightuserdata(*_luaState, asset.get());
lua_pushcclosure(*_luaState, &assetloader::resolveSyncedResource, 1);
lua_setfield(*_luaState, assetTableIndex, SyncedResourceFunctionName);
// Register import-dependency function
// Asset, Dependency import(string path)
lua_pushlightuserdata(*_luaState, asset);
lua_pushlightuserdata(*_luaState, asset.get());
lua_pushcclosure(*_luaState, &assetloader::importRequiredDependency, 1);
lua_setfield(*_luaState, assetTableIndex, ImportRequiredDependencyFunctionName);
// Register import-optional function
// Asset, Dependency importOptional(string path)
lua_pushlightuserdata(*_luaState, asset);
lua_pushlightuserdata(*_luaState, asset.get());
lua_pushcclosure(*_luaState, &assetloader::importOptionalDependency, 1);
lua_setfield(*_luaState, assetTableIndex, ImportOptionalDependencyFunctionName);
// Register export-dependency function
// export(string key, any value)
lua_pushlightuserdata(*_luaState, asset);
lua_pushlightuserdata(*_luaState, asset.get());
lua_pushcclosure(*_luaState, &assetloader::exportAsset, 1);
lua_setfield(*_luaState, assetTableIndex, ExportFunctionName);
// Register onInitialize function
// void onInitialize(function<void()> initializationFunction)
lua_pushlightuserdata(*_luaState, asset);
lua_pushlightuserdata(*_luaState, asset.get());
lua_pushcclosure(*_luaState, &assetloader::onInitialize, 1);
lua_setfield(*_luaState, assetTableIndex, OnInitializeFunctionName);
// Register onDeinitialize function
// void onDeinitialize(function<void()> deinitializationFunction)
lua_pushlightuserdata(*_luaState, asset);
lua_pushlightuserdata(*_luaState, asset.get());
lua_pushcclosure(*_luaState, &assetloader::onDeinitialize, 1);
lua_setfield(*_luaState, assetTableIndex, OnDeinitializeFunctionName);
// Register addSynchronization function
// void addSynchronization(table synchronization)
lua_pushlightuserdata(*_luaState, asset);
lua_pushlightuserdata(*_luaState, asset.get());
lua_pushcclosure(*_luaState, &assetloader::addSynchronization, 1);
lua_setfield(*_luaState, assetTableIndex, AddSynchronizationFunctionName);
@@ -422,10 +439,9 @@ void AssetLoader::popAsset() {
void AssetLoader::updateLuaGlobals() {
// Set `asset` lua global to point to the current asset table
std::shared_ptr<Asset> asset = _assetStack.back();
Asset* asset = _assetStack.back();
if (asset == _rootAsset.get()) {
if (asset == _rootAsset) {
lua_pushnil(*_luaState);
lua_setglobal(*_luaState, AssetGlobalVariableName);
return;
@@ -443,13 +459,13 @@ int AssetLoader::importRequiredDependencyLua(Asset* dependant) {
std::string assetName = luaL_checkstring(*_luaState, 1);
Asset* dependency = importRequiredDependency(assetName);
std::shared_ptr<Asset> dependency = importRequiredDependency(assetName);
if (!dependency) {
return luaL_error(*_luaState, "Asset '%s' not found", assetName.c_str());
}
addLuaDependencyTable(dependant, dependency);
addLuaDependencyTable(dependant, dependency.get());
// Get the exports table
lua_rawgeti(*_luaState, LUA_REGISTRYINDEX, _assetsTableRef);
@@ -476,13 +492,13 @@ int AssetLoader::importOptionalDependencyLua(Asset* dependant) {
std::string assetName = luaL_checkstring(*_luaState, 1);
bool enabled = lua_toboolean(*_luaState, 2);
Asset* dependency = importOptionalDependency(assetName, enabled);
std::shared_ptr<Asset> dependency = importOptionalDependency(assetName, enabled);
if (!dependency) {
return luaL_error(*_luaState, "Asset '%s' not found", assetName.c_str());
}
addLuaDependencyTable(dependant, dependency);
addLuaDependencyTable(dependant, dependency.get());
// Get the exports table
lua_rawgeti(*_luaState, LUA_REGISTRYINDEX, _assetsTableRef);