Improve asset lua interface. Simplify scene loading.

This commit is contained in:
Emil Axelsson
2017-07-06 16:40:35 +02:00
parent 8c642ab86d
commit ee36a97762
18 changed files with 266 additions and 608 deletions

View File

@@ -1,4 +0,0 @@
export ({
SceneGraphNodes = {
}
})

View File

@@ -1,8 +1,9 @@
Sun = import('sun');
local Sun = asset.import('sun');
local AssetHelper = asset.import('assethelper')
EarthBarycenter = {
asset.EarthBarycenter = {
Name = "EarthBarycenter",
Parent = Sun.SceneGraphNodes.SolarSystemBarycenter.Name,
Parent = Sun.SolarSystemBarycenter.Name,
Transform = {
Translation = {
Type = "SpiceTranslation",
@@ -13,22 +14,22 @@ EarthBarycenter = {
}
}
EarthInertial = {
asset.EarthInertial = {
-- The default reference frame for Earth-orbiting satellites
Name = "EarthInertial",
Parent = EarthBarycenter.Name,
Parent = asset.EarthBarycenter.Name,
Transform = {
Rotation = {
Type = "SpiceRotation",
SourceFrame = "J2000",
DestinationFrame = "GALACTIC",
}
},z
},
}
Earth = {
asset.Earth = {
Name = "Earth",
Parent = EarthBarycenter.Name,
Parent = asset.EarthBarycenter.Name,
Renderable = {
Type = "RenderablePlanet",
Frame = "IAU_EARTH",
@@ -40,10 +41,10 @@ Earth = {
},
Textures = {
Type = "simple",
Color = syncedResource("textures/earth_bluemarble.jpg"),
--Color = Sun.syncedResource("textures/sun.jpg"),
Night = syncedResource("textures/earth_night.jpg"),
Height = syncedResource("textures/earth_bluemarble_height.jpg")
--Color = resource("textures/earth_bluemarble.jpg"),
Color = asset.syncedResource("textures/earth_bluemarble.jpg"),
Night = asset.syncedResource("textures/earth_night.jpg"),
Height = asset.syncedResource("textures/earth_bluemarble_height.jpg")
},
Atmosphere = {
Type = "Nishita", -- for example, values missing etc etc
@@ -67,9 +68,9 @@ Earth = {
}
EarthTrail = {
asset.EarthTrail = {
Name = "EarthTrail",
Parent = Sun.SceneGraphNodes.SolarSystemBarycenter.Name,
Parent = Sun.SolarSystemBarycenter.Name,
Renderable = {
Type = "RenderableTrailOrbit",
Translation = {
@@ -88,25 +89,24 @@ EarthTrail = {
GuiName = "/Solar/EarthTrail",
}
EarthMarker = {
asset.EarthMarker = {
Name = "EarthMarker",
Parent = Earth.Name,
Parent = asset.Earth.Name,
Renderable = {
Type = "RenderablePlane",
Size = 3.0E11,
Origin = "Center",
Billboard = true,
Texture = syncedResource("textures/marker.png"),
Texture = asset.syncedResource("textures/marker.png"),
BlendMode = "Additive"
}
}
export({
SceneGraphNodes = {
EarthBarycenter = EarthBarycenter,
EarthInertial = EarthInertial,
Earth = Earth,
EarthTrail = EarthTrail,
EarthMarker = EarthMarker
}
AssetHelper.registerSceneGraphNodes(asset, {
asset.EarthBarycenter,
asset.EarthInertial,
asset.Earth,
asset.EarthTrail,
asset.EarthMarker
})

View File

@@ -1,19 +1,20 @@
Base = import('base')
--local Base = asset.import('base')
--BaseSpiceKernels = import('base-spice-kernels')
local AssetHelper = asset.import('assethelper')
SolarSystem = {
asset.SolarSystem = {
Name = "SolarSystem",
Parent = "Root"
}
SolarSystemBarycenter = {
asset.SolarSystemBarycenter = {
Name = "SolarSystemBarycenter",
Parent = SolarSystem.Name
Parent = asset.SolarSystem.Name
}
Sun = {
asset.Sun = {
Name = "Sun",
Parent = SolarSystemBarycenter.Name,
Parent = asset.SolarSystemBarycenter.Name,
Renderable = {
Type = "RenderablePlanet",
Frame = "IAU_SUN",
@@ -26,7 +27,7 @@ Sun = {
},
Textures = {
Type = "simple",
Color = syncedResource("textures/sun.jpg"),
Color = asset.syncedResource("textures/sun.jpg"),
},
PerformShading = false,
},
@@ -45,15 +46,15 @@ Sun = {
}
}
SunGlare = {
asset.SunGlare = {
Name = "SunGlare",
Parent = SolarSystemBarycenter.Name,
Parent = asset.SolarSystemBarycenter.Name,
Renderable = {
Type = "RenderablePlane",
Size = 1.3*10^10.5,
Origin = "Center",
Billboard = true,
Texture = syncedResource("textures/sun-glare.png"),
Texture = asset.syncedResource("textures/sun-glare.png"),
BlendMode = "Additive"
},
Transform = {
@@ -66,15 +67,15 @@ SunGlare = {
}
}
SunMarker = {
asset.SunMarker = {
Name = "SunMarker",
Parent = Sun.Name,
Parent = asset.Sun.Name,
Renderable = {
Type = "RenderablePlane",
Size = 3.0E11,
Origin = "Center",
Billboard = true,
Texture = syncedResource("textures/marker.png"),
Texture = asset.syncedResource("textures/marker.png"),
BlendMode = "Additive"
},
Transformation = {
@@ -85,12 +86,10 @@ SunMarker = {
}
}
export ({
SceneGraphNodes = {
SolarSystem = SolarSystem,
SolarSystemBarycenter = SolarSystemBarycenter,
Sun = Sun,
SunGlare = SunGlare,
SunMarker = SunMarker
}
AssetHelper.registerSceneGraphNodes(asset, {
asset.SolarSystem,
asset.SolarSystemBarycenter,
asset.Sun,
asset.SunGlare,
asset.SunMarker
})

View File

@@ -55,8 +55,10 @@ class NetworkEngine;
class ParallelConnection;
class RenderEngine;
class SettingsEngine;
class SceneManager;
class VirtualPropertyManager;
class Scene;
class AssetLoader;
class SceneLoader;
class SyncEngine;
class TimeManager;
@@ -182,7 +184,9 @@ private:
// Components
std::unique_ptr<ConfigurationManager> _configurationManager;
std::unique_ptr<SceneManager> _sceneManager;
std::unique_ptr<Scene> _scene;
std::unique_ptr<AssetLoader> _assetLoader;
std::unique_ptr<SceneLoader> _sceneLoader;
std::unique_ptr<DownloadManager> _downloadManager;
std::unique_ptr<LuaConsole> _console;
std::unique_ptr<ModuleEngine> _moduleEngine;

View File

@@ -38,7 +38,6 @@ namespace openspace {
namespace assetloader {
int importAsset(lua_State* state);
int exportAsset(lua_State* state);
int resolveLocalResource(lua_State* state);
int resolveSyncedResource(lua_State* state);
}
@@ -70,16 +69,13 @@ public:
friend int assetloader::resolveSyncedResource(lua_State* state);
int resolveSyncedResourceLua();
friend int assetloader::exportAsset(lua_State* state);
int exportAssetLua();
AssetLoader* _loader;
std::string _directory;
std::vector<Asset*> _dependencies;
std::vector<Asset*> _dependants;
};
AssetLoader(std::string assetRoot, std::string syncRoot);
AssetLoader(ghoul::lua::LuaState* _luaState, std::string assetRoot, std::string syncRoot);
~AssetLoader() = default;
@@ -87,7 +83,7 @@ public:
* Load an asset file.
*/
Asset* loadAsset(const std::string& identifier);
ghoul::lua::LuaState& luaState();
ghoul::lua::LuaState* luaState();
ghoul::filesystem::Directory currentDirectory();
Asset* rootAsset();
const std::string& syncRoot();
@@ -95,7 +91,7 @@ public:
private:
void pushAsset(Asset* asset);
void popAsset();
void updateGlobalLuaFunctions();
void updateLuaGlobals();
std::unique_ptr<Asset> _rootAsset;
std::map<std::string, std::unique_ptr<Asset>> _loadedAssets;
@@ -106,7 +102,7 @@ private:
friend int assetloader::importAsset(lua_State* state);
int importAssetLua();
ghoul::lua::LuaState _luaState;
ghoul::lua::LuaState* _luaState;
};

View File

@@ -65,11 +65,6 @@ public:
Scene();
~Scene();
/**
* Initalizes the SceneGraph
*/
void initialize();
/**
* Clear the scene graph,
* i.e. set the root node to nullptr and deallocate all scene graph nodes.
@@ -137,6 +132,11 @@ public:
*/
const std::map<std::string, SceneGraphNode*>& nodesByName() const;
/**
* Load a scene graph node from a dictionary and return it.
*/
SceneGraphNode* loadNode(const ghoul::Dictionary& nodeDictionary);
/**
* Returns the Lua library that contains all Lua functions available to change the
* scene graph. The functions contained are

View File

@@ -47,37 +47,10 @@ public:
/**
* Load a scene file.
*/
std::unique_ptr<Scene> loadScene(const std::string& path);
/**
* Import a directory of scene contents into an existing scene.
*/
std::vector<SceneGraphNode*> importDirectory(Scene& scene, const std::string& directory);
/**
* Import a scene graph node from a dictionary into an existing scene.
*/
SceneGraphNode* importNodeDictionary(Scene& scene, const ghoul::Dictionary& dictionary);
void loadScene(Scene* scene, const std::string& path);
private:
struct LoadedNode {
LoadedNode(
const std::string& nodeName,
const std::string& parentName,
const std::vector<std::string>& deps,
std::unique_ptr<SceneGraphNode> n
)
: name(nodeName)
, parent(parentName)
, dependencies(deps)
, node(std::move(n)) {}
std::string name;
std::string parent;
std::vector<std::string> dependencies;
std::unique_ptr<SceneGraphNode> node;
};
struct LoadedCamera {
LoadedCamera(
const std::string& parentName,
@@ -89,30 +62,15 @@ private:
std::unique_ptr<Camera> camera;
};
/**
* Load a scene graph node from a dictionary
*/
SceneLoader::LoadedNode loadNode(const ghoul::Dictionary& dictionary);
/**
* Load a mod file.
*/
std::vector<SceneLoader::LoadedNode> loadAsset(const std::string& path, lua_State* luaState);
/**
* Load a directory.
*/
std::vector<SceneLoader::LoadedNode> loadDirectory(const std::string& path, lua_State* luaState);
void loadDirectory(const std::string& path);
/**
* Load a camera from a dictionary
*/
SceneLoader::LoadedCamera loadCamera(const ghoul::Dictionary& dictionary);
/**
* Add loaded nodes to an existing scene
*/
std::vector<SceneGraphNode*> addLoadedNodes(Scene& scene, std::vector<SceneLoader::LoadedNode>&& nodes);
std::unique_ptr<SceneLoader::LoadedCamera> loadCamera(const ghoul::Dictionary& dictionary);
AssetLoader* _assetLoader;
};

View File

@@ -1,54 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___SCENEMANAGER___H__
#define __OPENSPACE_CORE___SCENEMANAGER___H__
#include <openspace/scene/assetloader.h>
#include <openspace/scene/sceneloader.h>
#include <vector>
#include <memory>
#include <string>
namespace openspace {
class Scene;
class SceneManager {
public:
SceneManager(std::string assetRoot, std::string syncRoot);
~SceneManager() = default;
Scene* loadScene(const std::string& path);
void unloadScene(Scene& scene);
void unloadAll();
private:
std::vector<std::unique_ptr<Scene>> _scenes;
AssetLoader _assetLoader;
SceneLoader _sceneLoader;
};
} // namespace
#endif // __OPENSPACE_CORE___SCENEMANAGER___H__

View File

@@ -71,6 +71,7 @@ public:
void deinitialize();
void initializeLuaState(lua_State* state);
ghoul::lua::LuaState* luaState();
void addLibrary(LuaLibrary library);
bool hasLibrary(const std::string& name);

View File

@@ -128,7 +128,6 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/scene/scene_doc.inl
${OPENSPACE_BASE_DIR}/src/scene/scene_lua.inl
${OPENSPACE_BASE_DIR}/src/scene/sceneloader.cpp
${OPENSPACE_BASE_DIR}/src/scene/scenemanager.cpp
${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode.cpp
${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode_doc.inl
${OPENSPACE_BASE_DIR}/src/scripting/lualibrary.cpp
@@ -275,7 +274,6 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/scene/scale.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/scene.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/sceneloader.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/scenemanager.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/scenegraphnode.h
${OPENSPACE_BASE_DIR}/include/openspace/scripting/lualibrary.h
${OPENSPACE_BASE_DIR}/include/openspace/scripting/script_helper.h

View File

@@ -48,7 +48,8 @@
#include <openspace/scene/rotation.h>
#include <openspace/scene/scale.h>
#include <openspace/scene/translation.h>
#include <openspace/scene/scenemanager.h>
#include <openspace/scene/sceneloader.h>
#include <openspace/scene/assetloader.h>
#include <openspace/util/factorymanager.h>
#include <openspace/util/task.h>
@@ -122,7 +123,7 @@ OpenSpaceEngine* OpenSpaceEngine::_engine = nullptr;
OpenSpaceEngine::OpenSpaceEngine(std::string programName,
std::unique_ptr<WindowWrapper> windowWrapper)
: _configurationManager(new ConfigurationManager)
, _sceneManager(nullptr)
, _scene(new Scene)
, _downloadManager(nullptr)
, _console(new LuaConsole)
, _moduleEngine(new ModuleEngine)
@@ -377,8 +378,10 @@ void OpenSpaceEngine::create(int argc, char** argv,
sgctArguments.insert(sgctArguments.begin() + 1, SgctConfigArgumentCommand);
sgctArguments.insert(sgctArguments.begin() + 2, absPath(sgctConfigurationPath));
// Set up scene manager
_engine->_sceneManager = std::make_unique<SceneManager>("${ASSETS}", "${SYNC}");
// Set up asset loader and scene loader
_engine->_assetLoader = std::make_unique<AssetLoader>(
OsEng.scriptEngine().luaState(), "${ASSETS}", "${SYNC}");
_engine->_sceneLoader = std::make_unique<SceneLoader>(_engine->_assetLoader.get());
}
void OpenSpaceEngine::destroy() {
@@ -402,7 +405,7 @@ void OpenSpaceEngine::destroy() {
_engine->_console->deinitialize();
_engine->_scriptEngine->deinitialize();
_engine->_sceneManager->unloadAll();
_engine->_scene = nullptr;
delete _engine;
FactoryManager::deinitialize();
@@ -552,7 +555,7 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) {
}
);
Scene* scene = nullptr;
if (scenePath != "") {
// Run start up scripts
try {
@@ -563,7 +566,17 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) {
}
// Load the scene
try {
scene = _sceneManager->loadScene(scenePath);
if (_scene) {
_syncEngine->removeSyncables(_timeManager->getSyncables());
_syncEngine->removeSyncables(_renderEngine->getSyncables());
_renderEngine->setScene(nullptr);
_renderEngine->setCamera(nullptr);
_interactionHandler->setCamera(nullptr);
}
_scene = std::make_unique<Scene>();
_renderEngine->setScene(_scene.get());
_sceneLoader->loadScene(_scene.get(), scenePath);
}
catch (const ghoul::FileNotFoundError& e) {
LERRORC(e.component, e.message);
@@ -587,26 +600,16 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) {
}
}
Scene* previousScene = _renderEngine->scene();
if (previousScene) {
_syncEngine->removeSyncables(_timeManager->getSyncables());
_syncEngine->removeSyncables(_renderEngine->getSyncables());
_renderEngine->setScene(nullptr);
_renderEngine->setCamera(nullptr);
_interactionHandler->setCamera(nullptr);
_sceneManager->unloadScene(*previousScene);
}
// Initialize the RenderEngine
_renderEngine->setScene(scene);
_renderEngine->setGlobalBlackOutFactor(0.0);
_renderEngine->startFading(1, 3.0);
if (scene) {
_renderEngine->setCamera(scene->camera());
scene->initialize();
_interactionHandler->setCamera(scene->camera());
if (_scene) {
_renderEngine->setCamera(_scene->camera());
_interactionHandler->setCamera(_scene->camera());
try {
runPostInitializationScripts(scenePath);
} catch (const ghoul::RuntimeError& e) {
@@ -624,7 +627,7 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) {
// If a PropertyDocumentationFile was specified, generate it now.
if (configurationManager().hasKey(ConfigurationManager::KeyPropertyDocumentation)) {
scene->writeDocumentation(
_scene->writeDocumentation(
absPath(configurationManager().value<std::string>(
ConfigurationManager::KeyPropertyDocumentation
))

View File

@@ -33,13 +33,17 @@
namespace {
const char* AssetFileSuffix = "asset";
const char* AssetGlobalVariableName = "asset";
const char* ImportFunctionName = "import";
const char* ExportFunctionName = "export";
const char* SyncedResourceFunctionName = "syncedResource";
const char* LocalResourceFunctionName = "localResource";
const char* _loggerCat = "AssetLoader";
const char* OnDeinitializeFunctionName = "onDeinitialize";
const char* AssetsTableName = "_assets";
const char* KeySceneGraphNodes = "SceneGraphNodes";
const char* _loggerCat = "AssetLoader";
}
namespace openspace {
@@ -50,11 +54,6 @@ int importAsset(lua_State* state) {
return assetLoader->importAssetLua();
}
int exportAsset(lua_State* state) {
AssetLoader::Asset* asset = (AssetLoader::Asset*)lua_touserdata(state, lua_upvalueindex(1));
return asset->exportAssetLua();
}
int resolveLocalResource(lua_State* state) {
AssetLoader::Asset* asset = (AssetLoader::Asset*)lua_touserdata(state, lua_upvalueindex(1));
return asset->resolveLocalResourceLua();
@@ -65,22 +64,23 @@ int resolveSyncedResource(lua_State* state) {
return asset->resolveSyncedResourceLua();
}
int noOperation(lua_State* state) {
return 0;
}
AssetLoader::AssetLoader(std::string assetRoot, std::string syncRoot)
: _rootAsset(std::make_unique<Asset>(this, std::move(assetRoot)))
, _syncRoot(std::move(syncRoot))
}
AssetLoader::AssetLoader(ghoul::lua::LuaState* luaState, std::string assetRoot, std::string syncRoot)
: _luaState(luaState)
, _rootAsset(std::make_unique<Asset>(this, std::move(assetRoot)))
, _syncRoot(std::move(syncRoot))
{
_assetStack.push_back(_rootAsset.get());
// Create _assets table.
lua_newtable(_luaState);
lua_setglobal(_luaState, AssetsTableName);
// Register import function
lua_pushlightuserdata(_luaState, this);
lua_pushcclosure(_luaState, &assetloader::importAsset, 1);
lua_setglobal(_luaState, ImportFunctionName);
lua_newtable(*_luaState);
lua_setglobal(*_luaState, AssetsTableName);
}
AssetLoader::Asset* AssetLoader::loadAsset(const std::string& name) {
@@ -105,7 +105,7 @@ AssetLoader::Asset* AssetLoader::loadAsset(const std::string& name) {
});
try {
ghoul::lua::runScriptFile(_luaState, asset->assetFilepath());
ghoul::lua::runScriptFile(*_luaState, asset->assetFilepath());
} catch (const ghoul::lua::LuaRuntimeException& e) {
LERROR(e.message << ": " << e.component);
}
@@ -118,7 +118,7 @@ ghoul::filesystem::Directory AssetLoader::currentDirectory() {
return _assetStack.back()->directory();
}
ghoul::lua::LuaState& AssetLoader::luaState() {
ghoul::lua::LuaState* AssetLoader::luaState() {
return _luaState;
}
@@ -132,16 +132,55 @@ const std::string& AssetLoader::syncRoot() {
void AssetLoader::pushAsset(Asset* asset) {
_assetStack.push_back(asset);
updateGlobalLuaFunctions();
// Push the global asset table to the lua stack.
lua_getglobal(*_luaState, AssetsTableName);
int globalTableIndex = lua_gettop(*_luaState);
// Create table for the current asset.
lua_newtable(*_luaState);
int assetTableIndex = lua_gettop(*_luaState);
// Register local resource function
lua_pushlightuserdata(*_luaState, asset);
lua_pushcclosure(*_luaState, &assetloader::resolveLocalResource, 1);
lua_setfield(*_luaState, assetTableIndex, LocalResourceFunctionName);
// Register synced resource function
lua_pushlightuserdata(*_luaState, asset);
lua_pushcclosure(*_luaState, &assetloader::resolveSyncedResource, 1);
lua_setfield(*_luaState, assetTableIndex, SyncedResourceFunctionName);
// Register import function
lua_pushlightuserdata(*_luaState, asset->loader());
lua_pushcclosure(*_luaState, &assetloader::importAsset, 1);
lua_setfield(*_luaState, assetTableIndex, ImportFunctionName);
// Register default onDeinitialize function
lua_pushcfunction(*_luaState, &assetloader::noOperation);
lua_setfield(*_luaState, assetTableIndex, OnDeinitializeFunctionName);
// Extend global asset table (pushed to the lua stack earlier) with this asset
lua_setfield(*_luaState, globalTableIndex, asset->id().c_str());
// Update lua globals
updateLuaGlobals();
}
void AssetLoader::popAsset() {
_assetStack.pop_back();
updateGlobalLuaFunctions();
updateLuaGlobals();
}
void AssetLoader::updateGlobalLuaFunctions() {
void AssetLoader::updateLuaGlobals() {
Asset* asset = _assetStack.back();
// Set `asset` lua global to point to the current asset table
lua_getglobal(*_luaState, AssetsTableName);
lua_getfield(*_luaState, -1, asset->id().c_str());
lua_setglobal(*_luaState, AssetGlobalVariableName);
}
/*void AssetLoader::updateGlobalLuaFunctions() {
Asset* asset = _assetStack.size() > 0 ? _assetStack.back() : nullptr;
// Register resolve functions
@@ -157,47 +196,25 @@ void AssetLoader::updateGlobalLuaFunctions() {
lua_pushlightuserdata(_luaState, asset);
lua_pushcclosure(_luaState, &assetloader::exportAsset, 1);
lua_setglobal(_luaState, ExportFunctionName);
}
}*/
int openspace::AssetLoader::importAssetLua() {
std::string assetName = luaL_checkstring(_luaState, -1);
int nArguments = lua_gettop(*_luaState);
if (nArguments != 1)
return luaL_error(*_luaState, "Expected %i arguments, got %i", 1, nArguments);
std::string assetName = luaL_checkstring(*_luaState, -1);
Asset* asset = loadAsset(assetName);
if (!asset) {
return luaL_error(_luaState, "Asset '%s' not found", assetName.c_str());
return luaL_error(*_luaState, "Asset '%s' not found", assetName.c_str());
}
const std::string assetId = asset->id();
lua_getglobal(_luaState, AssetsTableName);
lua_getfield(_luaState, -1, assetId.c_str());
lua_getglobal(*_luaState, AssetsTableName);
lua_getfield(*_luaState, -1, assetId.c_str());
return 1;
}
int AssetLoader::Asset::exportAssetLua() {
lua_State* state = _loader->luaState();
int nArguments = lua_gettop(state);
if (nArguments != 1)
return luaL_error(state, "Expected %i arguments, got %i", 1, nArguments);
const int type = lua_type(state, -1);
if (type != LUA_TTABLE)
return luaL_error(state, "Expected table, got %i", type);
// Extend this asset with resource methods
lua_getglobal(state, SyncedResourceFunctionName);
lua_setfield(state, -2, SyncedResourceFunctionName);
lua_getglobal(state, LocalResourceFunctionName);
lua_setfield(state, -2, LocalResourceFunctionName);
// Extend global asset table with this asset
lua_getglobal(state, AssetsTableName);
lua_insert(state, -2);
lua_setfield(state, -2, id().c_str());
return 0;
}
// Asset methods.
std::string AssetLoader::Asset::resolveLocalResource(std::string resourceName) {
@@ -218,36 +235,36 @@ std::string AssetLoader::Asset::resolveSyncedResource(std::string resourceName)
}
int AssetLoader::Asset::resolveLocalResourceLua() {
ghoul::lua::LuaState& state = loader()->luaState();
int nArguments = lua_gettop(state);
ghoul::lua::LuaState* state = loader()->luaState();
int nArguments = lua_gettop(*state);
if (nArguments != 1)
return luaL_error(state, "Expected %i arguments, got %i", 1, nArguments);
return luaL_error(*state, "Expected %i arguments, got %i", 1, nArguments);
const int type = lua_type(state, -1);
const int type = lua_type(*state, -1);
if (type != LUA_TSTRING)
return luaL_error(state, "Expected string, got %i", type);
return luaL_error(*state, "Expected string, got %i", type);
std::string resourceName = luaL_checkstring(state, -1);
std::string resourceName = luaL_checkstring(*state, -1);
std::string resolved = resolveLocalResource(resourceName);
lua_pushstring(state, resolved.c_str());
lua_pushstring(*state, resolved.c_str());
return 1;
}
int AssetLoader::Asset::resolveSyncedResourceLua() {
ghoul::lua::LuaState& state = loader()->luaState();
int nArguments = lua_gettop(state);
ghoul::lua::LuaState* state = loader()->luaState();
int nArguments = lua_gettop(*state);
if (nArguments != 1)
return luaL_error(state, "Expected %i arguments, got %i", 1, nArguments);
return luaL_error(*state, "Expected %i arguments, got %i", 1, nArguments);
const int type = lua_type(state, -1);
const int type = lua_type(*state, -1);
if (type != LUA_TSTRING)
return luaL_error(state, "Expected string, got %i", type);
return luaL_error(*state, "Expected string, got %i", type);
std::string resourceName = luaL_checkstring(state, -1);
std::string resourceName = luaL_checkstring(*state, -1);
std::string resolved = resolveSyncedResource(resourceName);
lua_pushstring(state, resolved.c_str());
lua_pushstring(*state, resolved.c_str());
return 1;
}
@@ -295,27 +312,27 @@ std::string AssetLoader::Asset::id() {
ghoul::Dictionary AssetLoader::Asset::dictionary() {
AssetLoader* assetLoader = loader();
ghoul::lua::LuaState& state = assetLoader->luaState();
ghoul::lua::LuaState* state = assetLoader->luaState();
ghoul::Dictionary dictionary;
lua_getglobal(state, AssetsTableName);
lua_getfield(state, -1, id().c_str());
lua_getglobal(*state, AssetsTableName);
lua_getfield(*state, -1, id().c_str());
if (lua_type(state, -1) != LUA_TTABLE) {
if (lua_type(*state, -1) != LUA_TTABLE) {
// The asset did not export anything.
// Return an empty dictionary.
return dictionary;
}
lua_getfield(state, -1, KeySceneGraphNodes);
lua_getfield(*state, -1, KeySceneGraphNodes);
if (lua_type(state, -1) != LUA_TTABLE) {
if (lua_type(*state, -1) != LUA_TTABLE) {
// The asset did not export any SceneGraphNodes.
// Return an empty dictionary.
return dictionary;
}
ghoul::lua::luaDictionaryFromState(state, dictionary);
ghoul::lua::luaDictionaryFromState(*state, dictionary);
return dictionary;
}

View File

@@ -32,7 +32,7 @@
#include <openspace/query/query.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scene/sceneloader.h>
#include <openspace/scene/nodeloader.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/scripting/script_helper.h>
#include <openspace/util/time.h>
@@ -71,6 +71,9 @@ namespace {
const char* KeyPositionObject = "Position";
const char* KeyViewOffset = "Offset";
const std::string KeyName = "Name";
const std::string KeyParentName = "Parent";
const char* MainTemplateFilename = "${OPENSPACE_DATA}/web/properties/main.hbs";
const char* PropertyOwnerTemplateFilename = "${OPENSPACE_DATA}/web/properties/propertyowner.hbs";
const char* PropertyTemplateFilename = "${OPENSPACE_DATA}/web/properties/property.hbs";
@@ -90,7 +93,11 @@ Scene::Scene()
},
JsFilename
)
{}
{
std::unique_ptr<SceneGraphNode> rootNode = std::make_unique<SceneGraphNode>();
rootNode->setName(SceneGraphNode::RootNodeName);
setRoot(std::move(rootNode));
}
Scene::~Scene(){
}
@@ -209,21 +216,6 @@ void Scene::sortTopologically() {
_topologicallySortedNodes = nodes;
}
void Scene::initialize() {
for (SceneGraphNode* node : _topologicallySortedNodes) {
try {
bool success = node->initialize();
if (success)
LDEBUG(node->name() << " initialized successfully!");
else
LWARNING(node->name() << " not initialized.");
}
catch (const ghoul::RuntimeError& e) {
LERRORC(std::string(_loggerCat) + "(" + e.component + ")", e.what());
}
}
}
void Scene::update(const UpdateData& data) {
for (SceneGraphNode* node : _topologicallySortedNodes) {
try {
@@ -275,6 +267,56 @@ const std::vector<SceneGraphNode*>& Scene::allSceneGraphNodes() const {
return _topologicallySortedNodes;
}
SceneGraphNode* Scene::loadNode(const ghoul::Dictionary& dict) {
std::vector<std::string> dependencyNames;
std::string nodeName = dict.value<std::string>(KeyName);
std::string parentName = dict.value<std::string>(KeyParentName);
std::unique_ptr<SceneGraphNode> node = SceneGraphNode::createFromDictionary(dict);
if (dict.hasKey(SceneGraphNode::KeyDependencies)) {
if (!dict.hasValue<ghoul::Dictionary>(SceneGraphNode::KeyDependencies)) {
LERROR("Dependencies did not have the corrent type");
}
ghoul::Dictionary nodeDependencies;
dict.getValue(SceneGraphNode::KeyDependencies, nodeDependencies);
std::vector<std::string> keys = nodeDependencies.keys();
for (const std::string& key : keys) {
std::string value = nodeDependencies.value<std::string>(key);
dependencyNames.push_back(value);
}
}
SceneGraphNode* parent = sceneGraphNode(parentName);
if (!parent) {
LERROR("Could not find parent '" + parentName + "' for '" + nodeName + "'");
return nullptr;
}
std::vector<SceneGraphNode*> dependencies;
bool foundAllDeps = true;
for (const auto& depName : dependencyNames) {
SceneGraphNode* dep = sceneGraphNode(depName);
if (!dep) {
LERROR("Could not find dependency '" + depName + "' for '" + nodeName + "'");
foundAllDeps = false;
continue;
}
dependencies.push_back(dep);
}
if (!foundAllDeps) {
return nullptr;
}
SceneGraphNode* rawNodePointer = node.get();
node->setDependencies(dependencies, SceneGraphNode::UpdateScene::No);
parent->attachChild(std::move(node));
return rawNodePointer;
}
std::string Scene::generateJson() const {
std::function<std::string(properties::PropertyOwner*)> createJson =
[&createJson](properties::PropertyOwner* owner) -> std::string

View File

@@ -356,13 +356,14 @@ int addSceneGraphNode(lua_State* L) {
return 0;
}
// Temporarily disabled.
SceneGraphNode* node = OsEng.renderEngine().scene()->loadNode(d);
if (!node) {
LERRORC("addSceneGraphNode", "Could not load node");
return 0;
}
//SceneLoader loader;
//SceneGraphNode* importedNode = loader.importNodeDictionary(*OsEng.renderEngine().scene(), d);
//importedNode->initialize();
//return 1;
node->initialize();
return 0;
}
int removeSceneGraphNode(lua_State* L) {

View File

@@ -375,6 +375,7 @@ void SceneGraphNode::setParent(SceneGraphNode& parent, UpdateScene updateScene)
}
void SceneGraphNode::attachChild(std::unique_ptr<SceneGraphNode> child, UpdateScene updateScene) {
ghoul_assert(child != nullptr, "Child may not be null");
ghoul_assert(child->parent() == nullptr, "Child may not already have a parent");
child->_parent = this;
@@ -382,10 +383,11 @@ void SceneGraphNode::attachChild(std::unique_ptr<SceneGraphNode> child, UpdateSc
child->setScene(_scene);
}
SceneGraphNode* childRaw = child.get();
_children.push_back(std::move(child));
if (_scene && updateScene) {
_scene->addNode(child.get());
_scene->addNode(childRaw);
}
}

View File

@@ -42,8 +42,6 @@ namespace {
const std::string AssetExtension = ".asset";
const std::string RootNodeName = "Root";
const std::string KeyName = "Name";
const std::string KeyParentName = "Parent";
const std::string KeyDependencies = "Dependencies";
const std::string KeyCamera = "Camera";
const std::string KeyCameraFocus = "Focus";
@@ -57,7 +55,7 @@ SceneLoader::SceneLoader(AssetLoader* assetLoader)
: _assetLoader(assetLoader)
{}
std::unique_ptr<Scene> SceneLoader::loadScene(const std::string& path) {
void SceneLoader::loadScene(Scene* scene, const std::string& path) {
// Set up lua state.
lua_State* state = ghoul::lua::createNewLuaState();
OnExit(
@@ -91,74 +89,30 @@ std::unique_ptr<Scene> SceneLoader::loadScene(const std::string& path) {
std::vector<std::string> keys = assetDictionary.keys();
//ghoul::filesystem::Directory oldDirectory = FileSys.currentDirectory();
std::vector<SceneLoader::LoadedNode> allNodes;
for (const std::string& key : keys) {
std::string fullAssetName = assetDictionary.value<std::string>(key);
std::replace(fullAssetName.begin(), fullAssetName.end(), '/', FileSys.PathSeparator);
std::string assetPath = FileSys.pathByAppendingComponent(assetsPath, fullAssetName);
std::vector<SceneLoader::LoadedNode> nodes = loadDirectory(assetPath, state);
std::move(nodes.begin(), nodes.end(), std::back_inserter(allNodes));
std::string assetName = assetDictionary.value<std::string>(key);
_assetLoader->loadAsset(assetName);
}
//FileSys.setCurrentDirectory(oldDirectory);
std::unique_ptr<Scene> scene = std::make_unique<Scene>();
std::unique_ptr<SceneGraphNode> rootNode = std::make_unique<SceneGraphNode>();
rootNode->setName(SceneGraphNode::RootNodeName);
scene->setRoot(std::move(rootNode));
addLoadedNodes(*scene, std::move(allNodes));
ghoul::Dictionary cameraDictionary;
sceneDictionary.getValue(KeyCamera, cameraDictionary);
LoadedCamera loadedCamera = loadCamera(cameraDictionary);
std::unique_ptr<LoadedCamera> loadedCamera = loadCamera(cameraDictionary);
auto& nodeMap = scene->nodesByName();
auto it = nodeMap.find(loadedCamera.parent);
auto it = nodeMap.find(loadedCamera->parent);
if (it != nodeMap.end()) {
loadedCamera.camera->setParent(it->second);
loadedCamera->camera->setParent(it->second);
} else {
LWARNING(
"Could not find the camera parent '" + loadedCamera.parent +
"Could not find the camera parent '" + loadedCamera->parent +
"'. Attaching camera to root node.");
loadedCamera.camera->setParent(scene->root());
loadedCamera->camera->setParent(scene->root());
}
scene->setCamera(std::move(loadedCamera.camera));
return scene;
scene->setCamera(std::move(loadedCamera->camera));
}
std::vector<SceneGraphNode*> SceneLoader::importDirectory(Scene& scene, const std::string& path) {
lua_State* state = ghoul::lua::createNewLuaState();
OnExit(
// Delete the Lua state at the end of the scope, no matter what.
[state]() {ghoul::lua::destroyLuaState(state); }
);
OsEng.scriptEngine().initializeLuaState(state);
std::string absDirectoryPath = absPath(path);
//ghoul::filesystem::Directory oldDirectory = FileSys.currentDirectory();
std::vector<SceneLoader::LoadedNode> nodes = loadDirectory(path, state);
//FileSys.setCurrentDirectory(oldDirectory);
return addLoadedNodes(scene, std::move(nodes));
}
SceneGraphNode* SceneLoader::importNodeDictionary(Scene& scene, const ghoul::Dictionary& dict) {
std::vector<SceneLoader::LoadedNode> loadedNodes;
loadedNodes.push_back(loadNode(dict));
std::vector<SceneGraphNode*> nodes = addLoadedNodes(scene, std::move(loadedNodes));
if (nodes.size() == 1) {
return nodes[0];
}
return nullptr;
}
SceneLoader::LoadedCamera SceneLoader::loadCamera(const ghoul::Dictionary& cameraDict) {
std::unique_ptr<SceneLoader::LoadedCamera> SceneLoader::loadCamera(const ghoul::Dictionary& cameraDict) {
std::string focus;
glm::vec3 cameraPosition;
glm::vec4 cameraRotation;
@@ -174,7 +128,7 @@ SceneLoader::LoadedCamera SceneLoader::loadCamera(const ghoul::Dictionary& camer
camera->setRotation(glm::dquat(
cameraRotation.x, cameraRotation.y, cameraRotation.z, cameraRotation.w));
LoadedCamera loadedCamera(focus, std::move(camera));
std::unique_ptr<LoadedCamera> loadedCamera = std::make_unique<LoadedCamera>(focus, std::move(camera));
if (!readSuccessful) {
throw Scene::InvalidSceneError(
@@ -184,208 +138,4 @@ SceneLoader::LoadedCamera SceneLoader::loadCamera(const ghoul::Dictionary& camer
return loadedCamera;
}
std::vector<SceneLoader::LoadedNode> SceneLoader::loadDirectory(
const std::string& path,
lua_State* luaState)
{
std::string::size_type pos = path.find_last_of(FileSys.PathSeparator);
if (pos == std::string::npos) {
LERROR("Error parsing directory name '" << path << "'");
return std::vector<SceneLoader::LoadedNode>();
}
std::string assetName = path.substr(pos + 1);
std::string assetFile = FileSys.pathByAppendingComponent(path, assetName) + AssetExtension;
if (FileSys.fileExists(assetFile)) {
// TODO: Get rid of changing the working directory (global state is bad) -- emiax
// This requires refactoring all renderables to not use relative paths in constructors.
FileSys.setCurrentDirectory(ghoul::filesystem::Directory(path));
// We have a asset file, so it is a direct include.
return loadAsset(assetName, luaState);
} else {
std::vector<SceneLoader::LoadedNode> allLoadedNodes;
// If we do not have a asset file, we have to include all subdirectories.
using ghoul::filesystem::Directory;
using std::string;
const Directory directory(path);
const std::string directoryPath = directory.path();
if (!FileSys.directoryExists(directoryPath)) {
LERROR("The directory " << directoryPath << " does not exist.");
return std::vector<SceneLoader::LoadedNode>();
}
for (const string& subdirectory : directory.readDirectories()) {
std::vector<SceneLoader::LoadedNode> loadedNodes = loadDirectory(subdirectory, luaState);
std::move(loadedNodes.begin(), loadedNodes.end(), std::back_inserter(allLoadedNodes));
}
return allLoadedNodes;
}
}
SceneLoader::LoadedNode SceneLoader::loadNode(const ghoul::Dictionary& dictionary) {
std::vector<std::string> dependencies;
std::string nodeName = dictionary.value<std::string>(KeyName);
std::string parentName = dictionary.value<std::string>(KeyParentName);
std::unique_ptr<SceneGraphNode> node = SceneGraphNode::createFromDictionary(dictionary);
if (dictionary.hasKey(SceneGraphNode::KeyDependencies)) {
if (!dictionary.hasValue<ghoul::Dictionary>(SceneGraphNode::KeyDependencies)) {
LERROR("Dependencies did not have the corrent type");
}
ghoul::Dictionary nodeDependencies;
dictionary.getValue(SceneGraphNode::KeyDependencies, nodeDependencies);
std::vector<std::string> keys = nodeDependencies.keys();
for (const std::string& key : keys) {
std::string value = nodeDependencies.value<std::string>(key);
dependencies.push_back(value);
}
}
return SceneLoader::LoadedNode(nodeName, parentName, dependencies, std::move(node));
}
std::vector<SceneLoader::LoadedNode> SceneLoader::loadAsset(const std::string& assetName, lua_State* luaState) {
AssetLoader::Asset* asset = _assetLoader->loadAsset(assetName);
const ghoul::Dictionary& assetDictionary = asset->dictionary();
std::vector<LoadedNode> loadedNodes;
std::vector<std::string> keys = assetDictionary.keys();
for (const std::string& key : keys) {
ghoul::Dictionary nodeDictionary;
if (!assetDictionary.getValue(key, nodeDictionary)) {
LERROR("Node dictionary did not have the corrent type");
continue;
}
try {
loadedNodes.push_back(loadNode(nodeDictionary));
} catch (ghoul::RuntimeError& e) {
LERROR("Failed loading node from " << assetName << ": " << e.message << ", " << e.component);
}
}
return loadedNodes;
}
std::vector<SceneGraphNode*> SceneLoader::addLoadedNodes(Scene& scene, std::vector<SceneLoader::LoadedNode>&& loadedNodes) {
std::map<std::string, SceneGraphNode*> existingNodes = scene.nodesByName();
std::map<std::string, SceneGraphNode*> addedNodes;
// Populate map of nodes to be added.
// Also track new branches of nodes that are attached
// to allow for recovery in case an invalid scene is generated.
for (auto& loadedNode : loadedNodes) {
std::string name = loadedNode.name;
if (existingNodes.count(name) > 0) {
LERROR("Node with name '" + name + "' already exists in scene");
continue;
}
if (addedNodes.count(name) > 0) {
LERROR("Duplicate node names '" + name + "' among loaded nodes");
}
SceneGraphNode* node = loadedNode.node.get();
addedNodes[name] = node;
}
// Find a node by name among the exising nodes and the added nodes.
auto findNode = [&existingNodes, &addedNodes](const std::string name) {
std::map<std::string, SceneGraphNode*>::iterator it;
if ((it = existingNodes.find(name)) != existingNodes.end()) {
return it->second;
}
if ((it = addedNodes.find(name)) != addedNodes.end()) {
return it->second;
}
return static_cast<SceneGraphNode*>(nullptr);
};
std::vector<SceneGraphNode*> attachedBranches;
std::vector<std::unique_ptr<SceneGraphNode>> badNodes;
// Attach each node to its parent and set up dependencies.
for (auto& loadedNode : loadedNodes) {
std::string parentName = loadedNode.parent;
std::vector<std::string> dependencyNames = loadedNode.dependencies;
SceneGraphNode* parent = findNode(parentName);
if (!parent) {
LERROR("Could not find parent '" + parentName + "' for '" + loadedNode.name + "'");
badNodes.push_back(std::move(loadedNode.node));
continue;
}
std::vector<SceneGraphNode*> dependencies;
bool foundAllDeps = true;
for (const auto& depName : dependencyNames) {
SceneGraphNode* dep = findNode(depName);
if (!dep) {
LERROR("Could not find dependency '" + depName + "' for '" + loadedNode.name + "'");
foundAllDeps = false;
continue;
}
dependencies.push_back(dep);
}
if (!foundAllDeps) {
badNodes.push_back(std::move(loadedNode.node));
continue;
}
SceneGraphNode* child = loadedNode.node.get();
parent->attachChild(std::move(loadedNode.node), SceneGraphNode::UpdateScene::No);
child->setDependencies(dependencies, SceneGraphNode::UpdateScene::No);
if (existingNodes.find(parentName) != existingNodes.end()) {
attachedBranches.push_back(child);
}
}
// Remove all bad nodes (parent or deps missing) and all their children and dependent nodes.
// Use unsorted set `visited` to avoid infinite loop in case of circular deps.
std::unordered_set<SceneGraphNode*> visited;
for (size_t i = 0; i < badNodes.size(); i++) {
auto& badNode = badNodes[i];
for (auto c : badNode->children()) {
visited.insert(c);
badNodes.push_back(badNode->detachChild(*c, SceneGraphNode::UpdateScene::No));
}
for (auto& d : badNode->dependentNodes()) {
SceneGraphNode* parent = d->parent();
if (visited.count(d) == 0) {
visited.insert(d);
if (parent) {
badNodes.push_back(parent->detachChild(*d, SceneGraphNode::UpdateScene::No));
}
}
}
}
// Warn for nodes that lack connection to the root.
for (auto& node : addedNodes) {
if (!node.second->scene()) {
LWARNING("Node '" << node.first << "' is not connected to the root and will not be added to the scene");
}
}
// Add the nodes to the scene.
for (auto& node : attachedBranches) {
scene.addNode(node, Scene::UpdateDependencies::No);
}
// Update dependencies: sort nodes topologically.
scene.updateDependencies();
// Return a vector of all added nodes.
std::vector<SceneGraphNode*> addedNodesVector;
std::transform(addedNodes.begin(), addedNodes.end(), std::back_inserter(addedNodesVector), [] (auto& pair) {
return pair.second;
});
return addedNodesVector;
}
}

View File

@@ -1,59 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/scene/scene.h>
#include <openspace/scene/sceneloader.h>
#include <openspace/scene/scenemanager.h>
#include <algorithm>
#include <memory>
namespace openspace {
SceneManager::SceneManager(std::string assetRoot, std::string syncRoot)
: _assetLoader(assetRoot, syncRoot)
, _sceneLoader(&_assetLoader)
{}
Scene* SceneManager::loadScene(const std::string& path) {
std::unique_ptr<Scene> scene = _sceneLoader.loadScene(path);
Scene* s = scene.get();
if (s) {
_scenes.push_back(std::move(scene));
}
return s;
}
void SceneManager::unloadScene(Scene& scene) {
_scenes.erase(std::remove_if(
_scenes.begin(), _scenes.end(), [&scene] (auto& s) {
return s.get() == &scene;
}), _scenes.end()
);
}
void SceneManager::unloadAll() {
_scenes.clear();
}
}

View File

@@ -93,6 +93,10 @@ void ScriptEngine::initializeLuaState(lua_State* state) {
}
}
ghoul::lua::LuaState * ScriptEngine::luaState() {
return &_state;
}
void ScriptEngine::addLibrary(LuaLibrary library) {
auto sortFunc = [](const LuaLibrary::Function& lhs, const LuaLibrary::Function& rhs)
{