Merge pull request #273 from OpenSpace/pr/scenegraph-refactor

Pr/scenegraph refactor
This commit is contained in:
Emil Axelsson
2017-04-04 16:31:17 +02:00
committed by GitHub
64 changed files with 1662 additions and 1862 deletions

View File

@@ -1,4 +1,9 @@
return {
-- Solar system module
{
Name = "SolarSystem",
Parent = "Root"
},
-- Sun barycenter module
{
Name = "SolarSystemBarycenter",

View File

@@ -55,6 +55,8 @@ class NetworkEngine;
class ParallelConnection;
class RenderEngine;
class SettingsEngine;
class SceneManager;
class SyncEngine;
class TimeManager;
class WindowWrapper;
@@ -95,7 +97,9 @@ public:
void externalControlCallback(const char* receivedChars, int size, int clientId);
void encode();
void decode();
void scheduleLoadScene(std::string scenePath);
void enableBarrier();
void disableBarrier();
@@ -167,6 +171,7 @@ private:
std::unique_ptr<WindowWrapper> windowWrapper);
~OpenSpaceEngine() = default;
void loadScene(const std::string& scenePath);
void gatherCommandlineArguments();
void loadFonts();
void runPreInitializationScripts(const std::string& sceneDescription);
@@ -174,6 +179,7 @@ private:
// Components
std::unique_ptr<ConfigurationManager> _configurationManager;
std::unique_ptr<SceneManager> _sceneManager;
std::unique_ptr<DownloadManager> _downloadManager;
std::unique_ptr<LuaConsole> _console;
std::unique_ptr<ModuleEngine> _moduleEngine;
@@ -193,6 +199,9 @@ private:
// Others
std::unique_ptr<properties::PropertyOwner> _globalPropertyNamespace;
bool _scheduledSceneSwitch;
std::string _scenePath;
struct {
std::vector<std::function<void()>> initialize;
std::vector<std::function<void()>> deinitialize;

View File

@@ -89,6 +89,11 @@ public:
*/
void removeSyncable(Syncable* syncable);
/**
* Remove multiple Syncables from being synchronized over the SGCT cluster
*/
void removeSyncables(const std::vector<Syncable*>& syncables);
private:
/**
* Vector of Syncables. The vectors ensures consistent encode/decode order

View File

@@ -25,13 +25,18 @@
#ifndef __OPENSPACE_CORE___RENDERENGINE___H__
#define __OPENSPACE_CORE___RENDERENGINE___H__
#include <openspace/scripting/scriptengine.h>
#include <openspace/performance/performancemanager.h>
#include <openspace/properties/optionproperty.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/properties/triggerproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/intproperty.h>
#include <openspace/properties/triggerproperty.h>
#include <openspace/rendering/raycastermanager.h>
#include <openspace/rendering/renderer.h>
#include <openspace/rendering/screenspacerenderable.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/syncdata.h>
@@ -48,17 +53,11 @@ class SharedMemory;
namespace openspace {
namespace performance {
class PerformanceManager;
}
// Forward declare to minimize dependencies
class Camera;
class SyncBuffer;
class Scene;
class Renderer;
class RaycasterManager;
class SceneManager;
class ScreenLog;
class ScreenSpaceRenderable;
@@ -77,14 +76,15 @@ public:
};
RenderEngine();
~RenderEngine();
~RenderEngine() = default;
void initialize();
void initializeGL();
void deinitialize();
void setSceneGraph(Scene* sceneGraph);
void setScene(Scene* scene);
Scene* scene();
void updateScene();
Camera* camera() const;
Renderer* renderer() const;
@@ -93,7 +93,7 @@ public:
// sgct wrapped functions
void updateSceneGraph();
void updateShaderPrograms();
void updateFade();
void updateRenderer();
@@ -144,6 +144,11 @@ public:
*/
void postRaycast(ghoul::opengl::ProgramObject& programObject);
/**
* Set the camera to use for rendering
*/
void setCamera(Camera* camera);
void setRendererFromString(const std::string& method);
@@ -181,9 +186,9 @@ private:
void renderInformation();
Camera* _mainCamera;
Scene* _sceneGraph;
RaycasterManager* _raycasterManager;
Camera* _camera;
Scene* _scene;
std::unique_ptr<RaycasterManager> _raycasterManager;
properties::BoolProperty _performanceMeasurements;
std::unique_ptr<performance::PerformanceManager> _performanceManager;

View File

@@ -33,8 +33,6 @@
#include <openspace/util/camera.h>
#include <openspace/util/updatestructures.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/scene/scenegraph.h>
#include <ghoul/opengl/programobject.h>
namespace ghoul { class Dictionary; }
@@ -49,61 +47,104 @@ class SceneGraphNode;
// SceneGraphFinishedLoading
class Scene {
public:
using UpdateDependencies = ghoul::Boolean;
struct InvalidSceneError : ghoul::RuntimeError {
/**
* \param message The reason that caused this exception to be thrown
* \param component The optional compoment that caused this exception to be thrown
* \pre message may not be empty
*/
explicit InvalidSceneError(const std::string& message, const std::string& component = "");
};
// constructors & destructor
Scene();
~Scene();
/**
* Initalizes the SceneGraph by loading modules from the ${SCENEPATH} directory
* Initalizes the SceneGraph
*/
bool initialize();
void initialize();
/*
* Clean up everything
/**
* Clear the scene graph,
* i.e. set the root node to nullptr and deallocate all scene graph nodes.
*/
bool deinitialize();
void clear();
/*
* Load the scenegraph from the provided folder
/**
* Set the root node of the scene
*/
void scheduleLoadSceneFile(const std::string& sceneDescriptionFilePath);
void clearSceneGraph();
void setRoot(std::unique_ptr<SceneGraphNode> root);
void loadModule(const std::string& modulePath);
/**
* Set the camera of the scene
*/
void setCamera(std::unique_ptr<Camera> camera);
/*
/**
* Return the camera
*/
Camera* camera() const;
/**
* Updates all SceneGraphNodes relative positions
*/
void update(const UpdateData& data);
/*
* Evaluates if the SceneGraphNodes are visible to the provided camera
/**
* Evaluate if the SceneGraphNodes are visible to the provided camera.
*/
void evaluate(Camera* camera);
/*
* Render visible SceneGraphNodes using the provided camera
/**
* Render visible SceneGraphNodes using the provided camera.
*/
void render(const RenderData& data, RendererTasks& tasks);
/*
* Returns the root SceneGraphNode
/**
* Return the root SceneGraphNode.
*/
SceneGraphNode* root() const;
/**
* Return the scenegraph node with the specified name or <code>nullptr</code> if that
* name does not exist
* name does not exist.
*/
SceneGraphNode* sceneGraphNode(const std::string& name) const;
std::vector<SceneGraphNode*> allSceneGraphNodes() const;
/**
* Add a node and all its children to the scene.
*/
void addNode(SceneGraphNode* node, UpdateDependencies updateDeps = UpdateDependencies::Yes);
SceneGraph& sceneGraph();
/**
* Remove a node and all its children from the scene.
*/
void removeNode(SceneGraphNode* node, UpdateDependencies updateDeps = UpdateDependencies::Yes);
/**
* Update dependencies.
*/
void updateDependencies();
/**
* Return a vector of all scene graph nodes in the scene.
*/
const std::vector<SceneGraphNode*>& allSceneGraphNodes() const;
/**
* Return a a map from name to scene graph node.
*/
const std::map<std::string, SceneGraphNode*>& nodesByName() const;
/**
* Output property documentation to a file.
*/
void writePropertyDocumentation(const std::string& filename, const std::string& type, const std::string& sceneFilename);
void addSceneGraphNode(SceneGraphNode* node){
_graph.addSceneGraphNode(node);
}
/**
* Returns the Lua library that contains all Lua functions available to change the
* scene graph. The functions contained are
@@ -116,39 +157,18 @@ public:
static documentation::Documentation Documentation();
private:
bool loadSceneInternal(const std::string& sceneDescriptionFilePath);
private:
void sortTopologically();
void writePropertyDocumentation(const std::string& filename, const std::string& type, const std::string& sceneFilename);
std::string _focus;
// actual scenegraph
SceneGraph _graph;
//SceneGraphNode* _root;
//std::vector<SceneGraphNode*> _nodes;
//std::map<std::string, SceneGraphNode*> _allNodes;
std::string _sceneGraphToLoad;
std::unique_ptr<SceneGraphNode> _root;
std::unique_ptr<Camera> _camera;
std::vector<SceneGraphNode*> _topologicallySortedNodes;
std::vector<SceneGraphNode*> _circularNodes;
std::map<std::string, SceneGraphNode*> _nodesByName;
std::mutex _programUpdateLock;
std::set<ghoul::opengl::ProgramObject*> _programsToUpdate;
std::vector<std::unique_ptr<ghoul::opengl::ProgramObject>> _programs;
typedef std::map<std::string, ghoul::Dictionary> NodeMap;
typedef std::multimap<std::string, std::string> DependencyMap;
typedef std::vector<std::string> LoadedList;
struct LoadMaps {
NodeMap nodes;
DependencyMap dependencies;
LoadedList loadedNodes;
};
void loadModules(const std::string& directory, const ghoul::Dictionary& dictionary);
void loadModule(LoadMaps& m,const std::string& modulePath, lua_State* state);
void loadNodes(const std::string& parentName, LoadMaps& m);
void loadNode(const ghoul::Dictionary& dictionary);
};
} // namespace openspace

View File

@@ -47,6 +47,8 @@ namespace documentation { struct Documentation; }
class SceneGraphNode : public properties::PropertyOwner {
public:
using UpdateScene = ghoul::Boolean;
struct PerformanceRecord {
long long renderTime; // time in ns
long long updateTimeRenderable; // time in ns
@@ -63,21 +65,32 @@ public:
SceneGraphNode();
~SceneGraphNode();
static SceneGraphNode* createFromDictionary(const ghoul::Dictionary& dictionary);
static std::unique_ptr<SceneGraphNode> createFromDictionary(const ghoul::Dictionary& dictionary);
bool initialize();
bool deinitialize();
void traversePreOrder(std::function<void(SceneGraphNode*)> fn);
void traversePostOrder(std::function<void(SceneGraphNode*)> fn);
void update(const UpdateData& data);
void evaluate(const Camera* camera, const psc& parentPosition = psc());
void render(const RenderData& data, RendererTasks& tasks);
void updateCamera(Camera* camera) const;
//void addNode(SceneGraphNode* child);
void attachChild(std::unique_ptr<SceneGraphNode> child, UpdateScene updateScene = UpdateScene::Yes);
std::unique_ptr<SceneGraphNode> detachChild(SceneGraphNode& child, UpdateScene updateScene = UpdateScene::Yes);
void setParent(SceneGraphNode& parent, UpdateScene updateScene = UpdateScene::Yes);
void addChild(SceneGraphNode* child);
void setParent(SceneGraphNode* parent);
//bool abandonChild(SceneGraphNode* child);
void addDependency(SceneGraphNode& dependency, UpdateScene updateScene = UpdateScene::Yes);
void removeDependency(SceneGraphNode& dependency, UpdateScene updateScene = UpdateScene::Yes);
void clearDependencies(UpdateScene updateScene = UpdateScene::Yes);
void setDependencies(const std::vector<SceneGraphNode*>& dependencies, UpdateScene updateScene = UpdateScene::Yes);
const std::vector<SceneGraphNode*>& dependencies() const;
const std::vector<SceneGraphNode*>& dependentNodes() const;
Scene* scene();
void setScene(Scene* scene);
glm::dvec3 position() const;
const glm::dmat3& rotationMatrix() const;
@@ -88,7 +101,7 @@ public:
double worldScale() const;
SceneGraphNode* parent() const;
const std::vector<SceneGraphNode*>& children() const;
std::vector<SceneGraphNode*> children() const;
PowerScaledScalar calculateBoundingSphere();
PowerScaledScalar boundingSphere() const;
@@ -104,14 +117,15 @@ public:
static documentation::Documentation Documentation();
private:
bool sphereInsideFrustum(const psc& s_pos, const PowerScaledScalar& s_rad, const Camera* camera);
glm::dvec3 calculateWorldPosition() const;
glm::dmat3 calculateWorldRotation() const;
double calculateWorldScale() const;
std::vector<SceneGraphNode*> _children;
std::vector<std::unique_ptr<SceneGraphNode>> _children;
SceneGraphNode* _parent;
std::vector<SceneGraphNode*> _dependencies;
std::vector<SceneGraphNode*> _dependentNodes;
Scene* _scene;
PerformanceRecord _performanceRecord;

View File

@@ -0,0 +1,119 @@
/*****************************************************************************************
* *
* 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___SCENELOADER___H__
#define __OPENSPACE_CORE___SCENELOADER___H__
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/camera.h>
#include <ghoul/misc/dictionary.h>
#include <ghoul/lua/ghoul_lua.h>
#include <memory>
#include <string>
namespace openspace {
class Scene;
class SceneLoader {
public:
SceneLoader() = default;
~SceneLoader() = default;
/**
* 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);
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,
std::unique_ptr<Camera> c
)
: parent(parentName)
, camera(std::move(c)) {}
std::string parent;
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> loadModule(const std::string& path, lua_State* luaState);
/**
* Load a directory.
*/
std::vector<SceneLoader::LoadedNode> loadDirectory(const std::string& path, lua_State* luaState);
/**
* 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);
};
}
#endif // __OPENSPACE_CORE___SCENELOADER___H__

View File

@@ -21,55 +21,28 @@
* 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___SCENEGRAPH___H__
#define __OPENSPACE_CORE___SCENEGRAPH___H__
#ifndef __OPENSPACE_CORE___SCENEMANAGER___H__
#define __OPENSPACE_CORE___SCENEMANAGER___H__
#include <vector>
#include <string>
#include <memory>
namespace openspace {
class SceneGraphNode;
class Scene;
class SceneGraph {
class SceneManager {
public:
SceneGraph();
~SceneGraph();
void clear();
bool loadFromFile(const std::string& sceneDescription);
// Returns if addition was successful
bool addSceneGraphNode(SceneGraphNode* node);
bool removeSceneGraphNode(SceneGraphNode* node);
const std::vector<SceneGraphNode*>& nodes() const;
SceneGraphNode* rootNode() const;
SceneGraphNode* sceneGraphNode(const std::string& name) const;
SceneManager() = default;
~SceneManager() = default;
Scene* loadScene(const std::string& path);
void unloadScene(Scene& scene);
void unloadAll();
private:
struct SceneGraphNodeInternal {
~SceneGraphNodeInternal();
SceneGraphNode* node = nullptr;
// From nodes that are dependent on this one
std::vector<SceneGraphNodeInternal*> incomingEdges;
// To nodes that this node depends on
std::vector<SceneGraphNodeInternal*> outgoingEdges;
};
bool nodeIsDependentOnRoot(SceneGraphNodeInternal* node);
bool sortTopologically();
SceneGraphNodeInternal* nodeByName(const std::string& name);
SceneGraphNode* _rootNode;
std::vector<SceneGraphNodeInternal*> _nodes;
std::vector<SceneGraphNode*> _topologicalSortedNodes;
std::vector<std::unique_ptr<Scene>> _scenes;
};
} // namespace openspace
}
#endif // __OPENSPACE_CORE___SCENEGRAPH___H__
#endif // __OPENSPACE_CORE___SCENEMANAGER___H__

View File

@@ -39,6 +39,7 @@
namespace openspace {
class SyncBuffer;
class SceneGraphNode;
/**
* This class still needs some more love. Suggested improvements:
@@ -92,6 +93,7 @@ public:
void setRotation(Quat rotation);
void setScaling(glm::vec2 scaling);
void setMaxFov(float fov);
void setParent(SceneGraphNode* parent);
// Relative mutators
void rotate(Quat rotation);
@@ -109,6 +111,7 @@ public:
const Quat& rotationQuaternion() const;
float maxFov() const;
float sinMaxFov() const;
SceneGraphNode* parent() const;
// @TODO this should simply be called viewMatrix!
// Or it needs to be changed so that it actually is combined. Right now it is
@@ -181,6 +184,7 @@ private:
SyncData<Vec3> _position;
SyncData<Quat> _rotation;
SyncData<glm::vec2> _scaling;
SceneGraphNode* _parent;
// _focusPosition to be removed

View File

@@ -265,8 +265,9 @@ void RenderablePlaneProjection::updatePlane(const Image& img, double currentTime
if (!_moving) {
SceneGraphNode* thisNode = OsEng.renderEngine().scene()->sceneGraphNode(_name);
SceneGraphNode* newParent = OsEng.renderEngine().scene()->sceneGraphNode(_target.node);
if (thisNode != nullptr && newParent != nullptr)
thisNode->setParent(newParent);
if (thisNode && newParent) {
thisNode->setParent(*newParent);
}
}
const GLfloat vertex_data[] = { // square of two triangles drawn within fov in target coordinates

View File

@@ -137,7 +137,7 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary&
documentation::testSpecificationAndThrow(
Documentation(),
dictionary,
"RenderablePlanetProject"
"RenderablePlanetProjection"
);
std::string name;

View File

@@ -124,7 +124,8 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/scene/scene.cpp
${OPENSPACE_BASE_DIR}/src/scene/scene_doc.inl
${OPENSPACE_BASE_DIR}/src/scene/scene_lua.inl
${OPENSPACE_BASE_DIR}/src/scene/scenegraph.cpp
${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
@@ -267,7 +268,8 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/scene/rotation.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/scale.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/scene.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/scenegraph.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

@@ -40,10 +40,14 @@
#include <openspace/network/networkengine.h>
#include <openspace/rendering/renderable.h>
#include <openspace/scripting/scriptscheduler.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/rotation.h>
#include <openspace/scene/scale.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/translation.h>
#include <openspace/scene/scenemanager.h>
#include <openspace/util/factorymanager.h>
#include <openspace/util/task.h>
#include <openspace/util/openspacemodule.h>
@@ -53,6 +57,7 @@
#include <openspace/util/transformationmanager.h>
#include <ghoul/ghoul.h>
#include <ghoul/misc/onscopeexit.h>
#include <ghoul/cmdparser/commandlineparser.h>
#include <ghoul/cmdparser/singlecommand.h>
#include <ghoul/filesystem/filesystem.h>
@@ -103,14 +108,18 @@ namespace openspace {
namespace properties {
class Property;
}
class Scene;
OpenSpaceEngine* OpenSpaceEngine::_engine = nullptr;
OpenSpaceEngine::OpenSpaceEngine(std::string programName,
std::unique_ptr<WindowWrapper> windowWrapper)
OpenSpaceEngine::OpenSpaceEngine(
std::string programName,
std::unique_ptr<WindowWrapper> windowWrapper)
: _configurationManager(new ConfigurationManager)
, _interactionHandler(new interaction::InteractionHandler)
, _renderEngine(new RenderEngine)
, _sceneManager(new SceneManager)
, _scriptEngine(new scripting::ScriptEngine)
, _scriptScheduler(new scripting::ScriptScheduler)
, _networkEngine(new NetworkEngine)
@@ -126,6 +135,8 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName,
, _parallelConnection(new ParallelConnection)
, _windowWrapper(std::move(windowWrapper))
, _globalPropertyNamespace(new properties::PropertyOwner(""))
, _scheduledSceneSwitch(false)
, _scenePath("")
, _runTime(0.0)
, _shutdown({false, 0.f, 0.f})
, _isFirstRenderingFirstFrame(true)
@@ -165,22 +176,6 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName,
TransformationManager::initialize();
}
//OpenSpaceEngine::~OpenSpaceEngine() {
// _globalPropertyNamespace = nullptr;
// _windowWrapper = nullptr;
// _parallelConnection = nullptr;
// _configurationManager = nullptr;
// _interactionHandler = nullptr;
// _renderEngine = nullptr;
// _scriptEngine = nullptr;
// _networkEngine = nullptr;
// _syncEngine = nullptr;
// _commandlineParser = nullptr;
// _console = nullptr;
// _moduleEngine = nullptr;
// _settingsEngine = nullptr;
//}
OpenSpaceEngine& OpenSpaceEngine::ref() {
ghoul_assert(_engine, "OpenSpaceEngine not created");
return *_engine;
@@ -194,7 +189,7 @@ void OpenSpaceEngine::create(int argc, char** argv,
ghoul_assert(windowWrapper != nullptr, "No Window Wrapper was provided");
requestClose = false;
ghoul::initialize();
// Initialize the LogManager and add the console log as this will be used every time
@@ -315,7 +310,7 @@ void OpenSpaceEngine::create(int argc, char** argv,
// Initialize the requested logs from the configuration file
_engine->configureLogging();
LINFOC("OpenSpace Version",
LINFOC("OpenSpace Version",
OPENSPACE_VERSION_MAJOR << "." <<
OPENSPACE_VERSION_MINOR << "." <<
OPENSPACE_VERSION_PATCH <<
@@ -381,15 +376,22 @@ void OpenSpaceEngine::destroy() {
func();
}
_engine->_syncEngine->removeSyncables(Time::ref().getSyncables());
_engine->_syncEngine->removeSyncables(_engine->_renderEngine->getSyncables());
_engine->_syncEngine->removeSyncable(_engine->_scriptEngine.get());
_engine->_moduleEngine->deinitialize();
_engine->_console->deinitialize();
_engine->_scriptEngine->deinitialize();
_engine->_sceneManager->unloadAll();
delete _engine;
FactoryManager::deinitialize();
Time::deinitialize();
SpiceManager::deinitialize();
ghoul::fontrendering::FontRenderer::deinitialize();
LogManager::deinitialize();
@@ -497,22 +499,124 @@ void OpenSpaceEngine::initialize() {
// Load a light and a monospaced font
loadFonts();
// Initialize the Scene
// @CLEANUP: This should become a unique_ptr that is either created inside the
// renderengine or moved into it ---abock
Scene* sceneGraph = new Scene;
sceneGraph->initialize();
std::string scenePath = "";
configurationManager().getValue(ConfigurationManager::KeyConfigScene, scenePath);
sceneGraph->scheduleLoadSceneFile(scenePath);
_renderEngine->initialize();
scheduleLoadScene(scenePath);
LINFO("Finished initializing");
}
void OpenSpaceEngine::scheduleLoadScene(std::string scenePath) {
_scheduledSceneSwitch = true;
_scenePath = std::move(scenePath);
}
void OpenSpaceEngine::loadScene(const std::string& scenePath) {
windowWrapper().setBarrier(false);
windowWrapper().setSynchronization(false);
OnExit(
[this]() {
windowWrapper().setSynchronization(true);
windowWrapper().setBarrier(true);
}
);
// Run start up scripts
try {
runPreInitializationScripts(scenePath);
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
}
Scene* scene;
try {
scene = _sceneManager->loadScene(scenePath);
} catch (const ghoul::FileNotFoundError& e) {
LERRORC(e.component, e.message);
return;
} catch (const Scene::InvalidSceneError& e) {
LERRORC(e.component, e.message);
return;
} catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
return;
}
Scene* previousScene = _renderEngine->scene();
if (previousScene) {
_syncEngine->removeSyncables(Time::ref().getSyncables());
_syncEngine->removeSyncables(_renderEngine->getSyncables());
_syncEngine->removeSyncable(_scriptEngine.get());
_renderEngine->setScene(nullptr);
_renderEngine->setCamera(nullptr);
_sceneManager->unloadScene(*previousScene);
}
// Initialize the RenderEngine
_renderEngine->setSceneGraph(sceneGraph);
_renderEngine->initialize();
_renderEngine->setScene(scene);
_renderEngine->setCamera(scene->camera());
_renderEngine->setGlobalBlackOutFactor(0.0);
_renderEngine->startFading(1, 3.0);
scene->initialize();
_interactionHandler->setCamera(scene->camera());
try {
runPostInitializationScripts(scenePath);
}
catch (const ghoul::RuntimeError& e) {
LFATALC(e.component, e.message);
}
// Write keyboard documentation.
{
const std::string KeyboardShortcutsType =
ConfigurationManager::KeyKeyboardShortcuts + "." +
ConfigurationManager::PartType;
const std::string KeyboardShortcutsFile =
ConfigurationManager::KeyKeyboardShortcuts + "." +
ConfigurationManager::PartFile;
std::string type, file;
const bool hasType = configurationManager().getValue(KeyboardShortcutsType, type);
const bool hasFile = configurationManager().getValue(KeyboardShortcutsFile, file);
if (hasType && hasFile) {
file = absPath(file);
interactionHandler().writeKeyboardDocumentation(type, file);
}
}
// If a PropertyDocumentationFile was specified, generate it now.
{
const std::string KeyPropertyDocumentationType =
ConfigurationManager::KeyPropertyDocumentation + '.' +
ConfigurationManager::PartType;
const std::string KeyPropertyDocumentationFile =
ConfigurationManager::KeyPropertyDocumentation + '.' +
ConfigurationManager::PartFile;
std::string type, file;
const bool hasType = configurationManager().getValue(KeyPropertyDocumentationType, type);
const bool hasFile = configurationManager().getValue(KeyPropertyDocumentationFile, file);
if (hasType && hasFile) {
file = absPath(file);
scene->writePropertyDocumentation(file, type, scenePath);
}
}
_renderEngine->setGlobalBlackOutFactor(0.0);
_renderEngine->startFading(1, 3.0);
for (const auto& func : _moduleCallbacks.initialize) {
func();
}
@@ -830,6 +934,11 @@ void OpenSpaceEngine::preSynchronization() {
LTRACE("OpenSpaceEngine::preSynchronization(begin)");
FileSys.triggerFilesystemEvents();
if (_scheduledSceneSwitch) {
loadScene(_scenePath);
_scheduledSceneSwitch = false;
}
if (_isFirstRenderingFirstFrame) {
_windowWrapper->setSynchronization(false);
}
@@ -850,7 +959,7 @@ void OpenSpaceEngine::preSynchronization() {
_interactionHandler->updateInputStates(dt);
_renderEngine->updateSceneGraph();
_renderEngine->updateScene();
_interactionHandler->updateCamera(dt);
_renderEngine->camera()->invalidateCache();
@@ -877,7 +986,7 @@ void OpenSpaceEngine::postSynchronizationPreDraw() {
_shutdown.timer -= static_cast<float>(_windowWrapper->averageDeltaTime());
}
_renderEngine->updateSceneGraph();
_renderEngine->updateScene();
_renderEngine->updateFade();
_renderEngine->updateRenderer();
_renderEngine->updateScreenSpaceRenderables();

View File

@@ -70,8 +70,9 @@ SettingsEngine::SettingsEngine()
void SettingsEngine::initialize() {
// Load all matching files in the Scene
// TODO: match regex with either with new ghoul readFiles or local code
std::string sceneDir = "${SCENE}";
std::vector<std::string> scenes = ghoul::filesystem::Directory(sceneDir).readFiles();
const std::string sceneDir = "${SCENE}";
const std::vector<std::string> scenes = ghoul::filesystem::Directory(sceneDir).readFiles();
for (std::size_t i = 0; i < scenes.size(); ++i) {
std::size_t found = scenes[i].find_last_of("/\\");
_scenes.addOption(static_cast<int>(i), scenes[i].substr(found + 1));
@@ -79,11 +80,11 @@ void SettingsEngine::initialize() {
// Set interaction to change ConfigurationManager and schedule the load
_scenes.onChange(
[this]() {
[this, sceneDir]() {
std::string sceneFile = _scenes.getDescriptionByValue(_scenes);
OsEng.configurationManager().setValue(
ConfigurationManager::KeyConfigScene, sceneFile);
OsEng.renderEngine().scene()->scheduleLoadSceneFile(sceneFile);
OsEng.scheduleLoadScene(sceneDir + "/" + sceneFile);
}
);
}
@@ -106,4 +107,4 @@ bool SettingsEngine::useDoubleBuffering() {
return _useDoubleBuffering.value();
}
} // namespace openspace
} // namespace openspace

View File

@@ -86,4 +86,10 @@ void SyncEngine::removeSyncable(Syncable* syncable) {
);
}
void SyncEngine::removeSyncables(const std::vector<Syncable*>& syncables) {
for (const auto& syncable : syncables) {
removeSyncable(syncable);
}
}
} // namespace openspace

View File

@@ -169,6 +169,7 @@ void InteractionHandler::setFocusNode(SceneGraphNode* node) {
void InteractionHandler::setCamera(Camera* camera) {
_camera = camera;
setFocusNode(_camera->parent());
}
void InteractionHandler::resetCameraDirection() {

View File

@@ -37,9 +37,8 @@
#include <openspace/rendering/abufferrenderer.h>
#include <openspace/rendering/framebufferrenderer.h>
#include <openspace/rendering/raycastermanager.h>
#include <openspace/rendering/renderer.h>
#include <openspace/rendering/screenspacerenderable.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scene/scene.h>
#include <openspace/util/camera.h>
#include <openspace/util/time.h>
#include <openspace/util/screenlog.h>
@@ -93,7 +92,7 @@ namespace openspace {
RenderEngine::RenderEngine()
: properties::PropertyOwner("RenderEngine")
, _mainCamera(nullptr)
, _camera(nullptr)
, _raycasterManager(nullptr)
, _performanceMeasurements("performanceMeasurements", "Performance Measurements")
, _frametimeType(
@@ -101,6 +100,7 @@ RenderEngine::RenderEngine()
"Type of the frametime display",
properties::OptionProperty::DisplayType::Dropdown
)
, _scene(nullptr)
, _showInfo("showInfo", "Show Render Information", true)
, _showLog("showLog", "Show the OnScreen log", true)
, _nAaSamples("nAaSamples", "Number of Antialiasing samples", 8, 1, 16)
@@ -109,7 +109,6 @@ RenderEngine::RenderEngine()
, _showFrameNumber("showFrameNumber", "Show Frame Number", false)
, _disableMasterRendering("disableMasterRendering", "Disable Master Rendering", false)
, _shouldTakeScreenshot(false)
, _sceneGraph(nullptr)
, _renderer(nullptr)
, _rendererImplementation(RendererImplementation::Invalid)
, _performanceManager(nullptr)
@@ -168,12 +167,23 @@ RenderEngine::RenderEngine()
addProperty(_disableMasterRendering);
}
RenderEngine::~RenderEngine() {
delete _sceneGraph;
_sceneGraph = nullptr;
void RenderEngine::setRendererFromString(const std::string& renderingMethod) {
_rendererImplementation = rendererFromString(renderingMethod);
delete _mainCamera;
delete _raycasterManager;
std::unique_ptr<Renderer> newRenderer = nullptr;
switch (_rendererImplementation) {
case RendererImplementation::Framebuffer:
newRenderer = std::make_unique<FramebufferRenderer>();
break;
case RendererImplementation::ABuffer:
newRenderer = std::make_unique<ABufferRenderer>();
break;
case RendererImplementation::Invalid:
LFATAL("Rendering method '" << renderingMethod << "' not among the available "
<< "rendering methods");
}
setRenderer(std::move(newRenderer));
}
void RenderEngine::initialize() {
@@ -201,20 +211,12 @@ void RenderEngine::initialize() {
);
}
_raycasterManager = new RaycasterManager();
_raycasterManager = std::make_unique<RaycasterManager>();
_nAaSamples = OsEng.windowWrapper().currentNumberOfAaSamples();
LINFO("Seting renderer from string: " << renderingMethod);
setRendererFromString(renderingMethod);
// init camera and set temporary position and scaling
_mainCamera = new Camera();
OsEng.interactionHandler().setCamera(_mainCamera);
if (_renderer) {
_renderer->setCamera(_mainCamera);
}
#ifdef GHOUL_USE_DEVIL
ghoul::io::TextureReader::ref().addReader(std::make_shared<ghoul::io::TextureReaderDevIL>());
#endif // GHOUL_USE_DEVIL
@@ -253,79 +255,6 @@ void RenderEngine::initializeGL() {
throw;
}
// ALL OF THIS HAS TO BE CHECKED
// ---abock
// sgct::Engine::instance()->setNearAndFarClippingPlanes(0.001f, 1000.0f);
// sgct::Engine::instance()->setNearAndFarClippingPlanes(0.1f, 30.0f);
// calculating the maximum field of view for the camera, used to
// determine visibility of objects in the scene graph
/* if (sgct::Engine::instance()->getCurrentRenderTarget() == sgct::Engine::NonLinearBuffer) {
// fisheye mode, looking upwards to the "dome"
glm::vec4 upDirection(0, 1, 0, 0);
// get the tilt and rotate the view
const float tilt = wPtr->getFisheyeTilt();
glm::mat4 tiltMatrix
= glm::rotate(glm::mat4(1.0f), tilt, glm::vec3(1.0f, 0.0f, 0.0f));
const glm::vec4 viewdir = tiltMatrix * upDirection;
// set the tilted view and the FOV
_mainCamera->setCameraDirection(glm::vec3(viewdir[0], viewdir[1], viewdir[2]));
_mainCamera->setMaxFov(wPtr->getFisheyeFOV());
_mainCamera->setLookUpVector(glm::vec3(0.0, 1.0, 0.0));
}
else {*/
// get corner positions, calculating the forth to easily calculate center
// glm::vec3 corners[4];
// sgct::SGCTWindow* wPtr = sgct::Engine::instance()->getWindowPtr(0);
// sgct_core::BaseViewport* vp = wPtr->getViewport(0);
// sgct_core::SGCTProjectionPlane* projectionPlane = vp->getProjectionPlane();
// corners[0] = *(projectionPlane->getCoordinatePtr(sgct_core::SGCTProjectionPlane::LowerLeft));
// corners[1] = *(projectionPlane->getCoordinatePtr(sgct_core::SGCTProjectionPlane::UpperLeft));
// corners[2] = *(projectionPlane->getCoordinatePtr(sgct_core::SGCTProjectionPlane::UpperRight));
// corners[3] = glm::vec3(corners[2][0], corners[0][1], corners[2][2]);
//
// const glm::vec3 center = (corners[0] + corners[1] + corners[2] + corners[3]);
////
//const glm::vec3 eyePosition = sgct_core::ClusterManager::instance()->getDefaultUserPtr()->getPos();
////// get viewdirection, stores the direction in the camera, used for culling
//const glm::vec3 viewdir = glm::normalize(eyePosition - center);
//const glm::vec3 upVector = corners[0] - corners[1];
//_mainCamera->setCameraDirection(glm::normalize(-viewdir));
//_mainCamera->setCameraDirection(glm::vec3(0.f, 0.f, -1.f));
//_mainCamera->setLookUpVector(glm::normalize(upVector));
//_mainCamera->setLookUpVector(glm::vec3(0.f, 1.f, 0.f));
// set the initial fov to be 0.0 which means everything will be culled
//float maxFov = 0.0f;
float maxFov = std::numeric_limits<float>::max();
//// for each corner
//for (int i = 0; i < 4; ++i) {
// // calculate radians to corner
// glm::vec3 dir = glm::normalize(eyePosition - corners[i]);
// float radsbetween = acos(glm::dot(viewdir, dir))
// / (glm::length(viewdir) * glm::length(dir));
// // the angle to a corner is larger than the current maxima
// if (radsbetween > maxFov) {
// maxFov = radsbetween;
// }
//}
_mainCamera->setMaxFov(maxFov);
//}
LINFO("Initializing Log");
std::unique_ptr<ScreenLog> log = std::make_unique<ScreenLog>(ScreenLogTimeToLive);
_log = log.get();
@@ -340,32 +269,10 @@ void RenderEngine::deinitialize() {
}
MissionManager::deinitialize();
_sceneGraph->clearSceneGraph();
}
void RenderEngine::setRendererFromString(const std::string& renderingMethod) {
_rendererImplementation = rendererFromString(renderingMethod);
std::unique_ptr<Renderer> newRenderer = nullptr;
switch (_rendererImplementation) {
case RendererImplementation::Framebuffer:
newRenderer = std::make_unique<FramebufferRenderer>();
break;
case RendererImplementation::ABuffer:
newRenderer = std::make_unique<ABufferRenderer>();
break;
case RendererImplementation::Invalid:
LFATAL("Rendering method '" << renderingMethod << "' not among the available "
<< "rendering methods");
}
setRenderer(std::move(newRenderer));
}
void RenderEngine::updateSceneGraph() {
LTRACE("RenderEngine::updateSceneGraph(begin)");
_sceneGraph->update({
void RenderEngine::updateScene() {
_scene->update({
glm::dvec3(0),
glm::dmat3(1),
1,
@@ -376,13 +283,7 @@ void RenderEngine::updateSceneGraph() {
_performanceManager != nullptr
});
_sceneGraph->evaluate(_mainCamera);
//Allow focus node to update camera (enables camera-following)
//FIX LATER: THIS CAUSES MASTER NODE TO BE ONE FRAME AHEAD OF SLAVES
//if (const SceneGraphNode* node = OsEng.ref().interactionHandler().focusNode()){
//node->updateCamera(_mainCamera);
//}
_scene->evaluate(_camera);
LTRACE("RenderEngine::updateSceneGraph(end)");
}
@@ -468,8 +369,7 @@ void RenderEngine::updateFade() {
0.f,
_currentFadeTime / _fadeDuration
);
}
else {
} else {
_globalBlackOutFactor = glm::smoothstep(
0.f,
1.f,
@@ -483,11 +383,12 @@ void RenderEngine::updateFade() {
}
}
void RenderEngine::render(const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix)
{
void RenderEngine::render(const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix) {
LTRACE("RenderEngine::render(begin)");
_mainCamera->sgctInternal.setViewMatrix(viewMatrix);
_mainCamera->sgctInternal.setProjectionMatrix(projectionMatrix);
_camera->sgctInternal.setViewMatrix(viewMatrix);
_camera->sgctInternal.setProjectionMatrix(projectionMatrix);
WindowWrapper& wrapper = OsEng.windowWrapper();
@@ -562,20 +463,29 @@ void RenderEngine::postDraw() {
}
Scene* RenderEngine::scene() {
ghoul_assert(_sceneGraph, "Scenegraph not initialized");
return _sceneGraph;
return _scene;
}
RaycasterManager& RenderEngine::raycasterManager() {
return *_raycasterManager;
}
void RenderEngine::setSceneGraph(Scene* sceneGraph) {
_sceneGraph = sceneGraph;
void RenderEngine::setScene(Scene* scene) {
_scene = scene;
if (_renderer) {
_renderer->setScene(scene);
}
}
void RenderEngine::setCamera(Camera* camera) {
_camera = camera;
if (_renderer) {
_renderer->setCamera(camera);
}
}
Camera* RenderEngine::camera() const {
return _mainCamera;
return _camera;
}
Renderer* RenderEngine::renderer() const {
@@ -735,8 +645,8 @@ void RenderEngine::setRenderer(std::unique_ptr<Renderer> renderer) {
_renderer->setResolution(renderingResolution());
_renderer->setNAaSamples(_nAaSamples);
_renderer->initialize();
_renderer->setCamera(_mainCamera);
_renderer->setScene(_sceneGraph);
_renderer->setCamera(_camera);
_renderer->setScene(_scene);
}
scripting::LuaLibrary RenderEngine::luaLibrary() {
@@ -983,21 +893,12 @@ void RenderEngine::renderInformation() {
#ifdef OPENSPACE_MODULE_NEWHORIZONS_ENABLED
//<<<<<<< HEAD
bool hasNewHorizons = scene()->sceneGraphNode("NewHorizons");
double currentTime = Time::ref().j2000Seconds();
if (MissionManager::ref().hasCurrentMission()) {
const Mission& mission = MissionManager::ref().currentMission();
//=======
// bool hasNewHorizons = scene()->sceneGraphNode("NewHorizons");
// double currentTime = Time::ref().currentTime();
//>>>>>>> develop
//
// if (MissionManager::ref().hasCurrentMission()) {
//
// const Mission& mission = MissionManager::ref().currentMission();
if (mission.phases().size() > 0) {
static const glm::vec4 nextMissionColor(0.7, 0.3, 0.3, 1);
@@ -1353,7 +1254,11 @@ void RenderEngine::renderScreenLog() {
}
std::vector<Syncable*> RenderEngine::getSyncables(){
return _mainCamera->getSyncables();
if (_camera) {
return _camera->getSyncables();
} else {
return std::vector<Syncable*>();
}
}
void RenderEngine::sortScreenspaceRenderables() {

View File

@@ -32,6 +32,7 @@
#include <openspace/query/query.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scene/sceneloader.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/scripting/script_helper.h>
#include <openspace/util/time.h>
@@ -54,6 +55,8 @@
#include <numeric>
#include <fstream>
#include <string>
#include <stack>
#include <unordered_map>
#include "scene_doc.inl"
#include "scene_lua.inl"
@@ -79,69 +82,141 @@ namespace {
namespace openspace {
Scene::Scene()
: _focus(SceneGraphNode::RootNodeName)
{}
Scene::Scene() {}
Scene::~Scene() {
deinitialize();
Scene::~Scene() {}
void Scene::setRoot(std::unique_ptr<SceneGraphNode> root) {
if (_root) {
removeNode(_root.get());
}
_root = std::move(root);
_root->setScene(this);
addNode(_root.get());
}
bool Scene::initialize() {
LDEBUG("Initializing SceneGraph");
return true;
void Scene::setCamera(std::unique_ptr<Camera> camera) {
_camera = std::move(camera);
}
bool Scene::deinitialize() {
clearSceneGraph();
return true;
Camera* Scene::camera() const {
return _camera.get();
}
void Scene::update(const UpdateData& data) {
if (!_sceneGraphToLoad.empty()) {
OsEng.renderEngine().scene()->clearSceneGraph();
try {
loadSceneInternal(_sceneGraphToLoad);
void Scene::addNode(SceneGraphNode* node, UpdateDependencies updateDeps) {
// Add the node and all its children.
node->traversePreOrder([this](SceneGraphNode* n) {
_topologicallySortedNodes.push_back(n);
_nodesByName[n->name()] = n;
});
if (updateDeps) {
updateDependencies();
}
}
// Reset the InteractionManager to Orbital/default mode
// TODO: Decide if it belongs in the scene and/or how it gets reloaded
//OsEng.interactionHandler().setInteractionMode("Orbital");
void Scene::removeNode(SceneGraphNode* node, UpdateDependencies updateDeps) {
// Remove the node and all its children.
node->traversePostOrder([this](SceneGraphNode* node) {
_topologicallySortedNodes.erase(
std::remove(_topologicallySortedNodes.begin(), _topologicallySortedNodes.end(), node),
_topologicallySortedNodes.end()
);
_nodesByName.erase(node->name());
});
if (updateDeps) {
updateDependencies();
}
}
// After loading the scene, the keyboard bindings have been set
const std::string KeyboardShortcutsType =
ConfigurationManager::KeyKeyboardShortcuts + "." +
ConfigurationManager::PartType;
void Scene::updateDependencies() {
sortTopologically();
}
const std::string KeyboardShortcutsFile =
ConfigurationManager::KeyKeyboardShortcuts + "." +
ConfigurationManager::PartFile;
void Scene::sortTopologically() {
_topologicallySortedNodes.insert(
_topologicallySortedNodes.end(),
std::make_move_iterator(_circularNodes.begin()),
std::make_move_iterator(_circularNodes.end())
);
_circularNodes.clear();
ghoul_assert(_topologicallySortedNodes.size() == _nodesByName.size(), "Number of scene graph nodes is inconsistent");
if (_topologicallySortedNodes.empty())
return;
std::string type;
std::string file;
bool hasType = OsEng.configurationManager().getValue(
KeyboardShortcutsType, type
);
bool hasFile = OsEng.configurationManager().getValue(
KeyboardShortcutsFile, file
);
if (hasType && hasFile) {
OsEng.interactionHandler().writeKeyboardDocumentation(type, file);
}
LINFO("Loaded " << _sceneGraphToLoad);
_sceneGraphToLoad = "";
}
catch (const ghoul::RuntimeError& e) {
LERROR(e.what());
_sceneGraphToLoad = "";
return;
// Only the Root node can have an in-degree of 0
SceneGraphNode* root = _nodesByName[SceneGraphNode::RootNodeName];
if (!root) {
throw Scene::InvalidSceneError("No root node found");
}
std::unordered_map<SceneGraphNode*, size_t> inDegrees;
for (SceneGraphNode* node : _topologicallySortedNodes) {
size_t inDegree = node->dependencies().size();
if (node->parent() != nullptr) {
inDegree++;
inDegrees[node] = inDegree;
}
}
for (SceneGraphNode* node : _graph.nodes()) {
std::stack<SceneGraphNode*> zeroInDegreeNodes;
zeroInDegreeNodes.push(root);
std::vector<SceneGraphNode*> nodes;
nodes.reserve(_topologicallySortedNodes.size());
while (!zeroInDegreeNodes.empty()) {
SceneGraphNode* node = zeroInDegreeNodes.top();
nodes.push_back(node);
zeroInDegreeNodes.pop();
for (SceneGraphNode* n : node->dependentNodes()) {
auto it = inDegrees.find(n);
it->second -= 1;
if (it->second == 0) {
zeroInDegreeNodes.push(n);
inDegrees.erase(it);
}
}
for (SceneGraphNode* n : node->children()) {
auto it = inDegrees.find(n);
it->second -= 1;
if (it->second == 0) {
zeroInDegreeNodes.push(n);
inDegrees.erase(it);
}
}
}
if (inDegrees.size() > 0) {
LERROR("The scene contains circular dependencies. " << inDegrees.size() << " nodes will be disabled.");
}
for (auto it : inDegrees) {
_circularNodes.push_back(it.first);
}
_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 {
LTRACE("Scene::update(begin '" + node->name() + "')");
node->update(data);
@@ -154,299 +229,54 @@ void Scene::update(const UpdateData& data) {
}
void Scene::evaluate(Camera* camera) {
for (SceneGraphNode* node : _graph.nodes())
node->evaluate(camera);
//_root->evaluate(camera);
for (SceneGraphNode* node : _topologicallySortedNodes) {
try {
LTRACE("Scene::evaluate(begin '" + node->name() + "')");
node->evaluate(camera);
LTRACE("Scene::evaluate(end '" + node->name() + "')");
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.what());
}
}
}
void Scene::render(const RenderData& data, RendererTasks& tasks) {
for (SceneGraphNode* node : _graph.nodes()) {
LTRACE("Scene::render(begin '" + node->name() + "')");
node->render(data, tasks);
LTRACE("Scene::render(end '" + node->name() + "')");
for (SceneGraphNode* node : _topologicallySortedNodes) {
try {
LTRACE("Scene::render(begin '" + node->name() + "')");
node->render(data, tasks);
LTRACE("Scene::render(end '" + node->name() + "')");
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.what());
}
}
}
void Scene::scheduleLoadSceneFile(const std::string& sceneDescriptionFilePath) {
_sceneGraphToLoad = sceneDescriptionFilePath;
}
void Scene::clearSceneGraph() {
void Scene::clear() {
LINFO("Clearing current scene graph");
// deallocate the scene graph. Recursive deallocation will occur
_graph.clear();
//if (_root) {
// _root->deinitialize();
// delete _root;
// _root = nullptr;
//}
// _nodes.erase(_nodes.begin(), _nodes.end());
// _allNodes.erase(_allNodes.begin(), _allNodes.end());
_focus.clear();
_root = nullptr;
}
bool Scene::loadSceneInternal(const std::string& sceneDescriptionFilePath) {
ghoul::Dictionary dictionary;
OsEng.windowWrapper().setSynchronization(false);
OnExit(
[](){ OsEng.windowWrapper().setSynchronization(true); }
);
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);
ghoul::lua::loadDictionaryFromFile(
sceneDescriptionFilePath,
dictionary,
state
);
// Perform testing against the documentation/specification
openspace::documentation::testSpecificationAndThrow(
Scene::Documentation(),
dictionary,
"Scene"
);
_graph.loadFromFile(sceneDescriptionFilePath);
// Initialize all nodes
for (SceneGraphNode* node : _graph.nodes()) {
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());
}
}
// update the position of all nodes
// TODO need to check this; unnecessary? (ab)
for (SceneGraphNode* node : _graph.nodes()) {
try {
node->update({
glm::dvec3(0),
glm::dmat3(1),
1,
Time::ref().j2000Seconds() });
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
}
}
for (auto it = _graph.nodes().rbegin(); it != _graph.nodes().rend(); ++it)
(*it)->calculateBoundingSphere();
// Read the camera dictionary and set the camera state
ghoul::Dictionary cameraDictionary;
if (dictionary.getValue(KeyCamera, cameraDictionary)) {
OsEng.interactionHandler().setCameraStateFromDictionary(cameraDictionary);
}
// If a PropertyDocumentationFile was specified, generate it now
const std::string KeyPropertyDocumentationType =
ConfigurationManager::KeyPropertyDocumentation + '.' +
ConfigurationManager::PartType;
const std::string KeyPropertyDocumentationFile =
ConfigurationManager::KeyPropertyDocumentation + '.' +
ConfigurationManager::PartFile;
const bool hasType = OsEng.configurationManager().hasKey(KeyPropertyDocumentationType);
const bool hasFile = OsEng.configurationManager().hasKey(KeyPropertyDocumentationFile);
if (hasType && hasFile) {
std::string propertyDocumentationType;
OsEng.configurationManager().getValue(KeyPropertyDocumentationType, propertyDocumentationType);
std::string propertyDocumentationFile;
OsEng.configurationManager().getValue(KeyPropertyDocumentationFile, propertyDocumentationFile);
propertyDocumentationFile = absPath(propertyDocumentationFile);
writePropertyDocumentation(propertyDocumentationFile, propertyDocumentationType, sceneDescriptionFilePath);
}
OsEng.runPostInitializationScripts(sceneDescriptionFilePath);
OsEng.enableBarrier();
return true;
const std::map<std::string, SceneGraphNode*>& Scene::nodesByName() const {
return _nodesByName;
}
//void Scene::loadModules(
// const std::string& directory,
// const ghoul::Dictionary& dictionary)
//{
// // Struct containing dependencies and nodes
// LoadMaps m;
//
// // Get the common directory
// std::string commonDirectory(_defaultCommonDirectory);
// dictionary.getValue(constants::scenegraph::keyCommonFolder, commonDirectory);
// FileSys.registerPathToken(_commonModuleToken, commonDirectory);
//
// lua_State* state = ghoul::lua::createNewLuaState();
// OsEng.scriptEngine()->initializeLuaState(state);
//
// LDEBUG("Loading common module folder '" << commonDirectory << "'");
// // Load common modules into LoadMaps struct
// loadModule(m, FileSys.pathByAppendingComponent(directory, commonDirectory), state);
//
// // Load the rest of the modules into LoadMaps struct
// ghoul::Dictionary moduleDictionary;
// if (dictionary.getValue(constants::scenegraph::keyModules, moduleDictionary)) {
// std::vector<std::string> keys = moduleDictionary.keys();
// std::sort(keys.begin(), keys.end());
// for (const std::string& key : keys) {
// std::string moduleFolder;
// if (moduleDictionary.getValue(key, moduleFolder)) {
// loadModule(m, FileSys.pathByAppendingComponent(directory, moduleFolder), state);
// }
// }
// }
//
// // Load and construct scenegraphnodes from LoadMaps struct
// loadNodes(SceneGraphNode::RootNodeName, m);
//
// // Remove loaded nodes from dependency list
// for(const auto& name: m.loadedNodes) {
// m.dependencies.erase(name);
// }
//
// // Check to see what dependencies are not resolved.
// for(auto& node: m.dependencies) {
// LWARNING(
// "'" << node.second << "'' not loaded, parent '"
// << node.first << "' not defined!");
// }
//}
//void Scene::loadModule(LoadMaps& m,const std::string& modulePath, lua_State* state) {
// auto pos = modulePath.find_last_of(ghoul::filesystem::FileSystem::PathSeparator);
// if (pos == modulePath.npos) {
// LERROR("Bad format for module path: " << modulePath);
// return;
// }
//
// std::string fullModule = modulePath + modulePath.substr(pos) + _moduleExtension;
// LDEBUG("Loading nodes from: " << fullModule);
//
// ghoul::filesystem::Directory oldDirectory = FileSys.currentDirectory();
// FileSys.setCurrentDirectory(modulePath);
//
// ghoul::Dictionary moduleDictionary;
// ghoul::lua::loadDictionaryFromFile(fullModule, moduleDictionary, state);
// std::vector<std::string> keys = moduleDictionary.keys();
// for (const std::string& key : keys) {
// if (!moduleDictionary.hasValue<ghoul::Dictionary>(key)) {
// LERROR("SceneGraphElement '" << key << "' is not a table in module '"
// << fullModule << "'");
// continue;
// }
//
// ghoul::Dictionary element;
// std::string nodeName;
// std::string parentName;
//
// moduleDictionary.getValue(key, element);
// element.setValue(constants::scenegraph::keyPathModule, modulePath);
//
// element.getValue(constants::scenegraphnode::keyName, nodeName);
// element.getValue(constants::scenegraphnode::keyParentName, parentName);
//
// m.nodes[nodeName] = element;
// m.dependencies.emplace(parentName,nodeName);
// }
//
// FileSys.setCurrentDirectory(oldDirectory);
//}
//void Scene::loadNodes(const std::string& parentName, LoadMaps& m) {
// auto eqRange = m.dependencies.equal_range(parentName);
// for (auto it = eqRange.first; it != eqRange.second; ++it) {
// auto node = m.nodes.find((*it).second);
// loadNode(node->second);
// loadNodes((*it).second, m);
// }
// m.loadedNodes.emplace_back(parentName);
//}
//
//void Scene::loadNode(const ghoul::Dictionary& dictionary) {
// SceneGraphNode* node = SceneGraphNode::createFromDictionary(dictionary);
// if(node) {
// _allNodes.emplace(node->name(), node);
// _nodes.push_back(node);
// }
//}
//void SceneGraph::loadModule(const std::string& modulePath) {
// auto pos = modulePath.find_last_of(ghoul::filesystem::FileSystem::PathSeparator);
// if (pos == modulePath.npos) {
// LERROR("Bad format for module path: " << modulePath);
// return;
// }
//
// std::string fullModule = modulePath + modulePath.substr(pos) + _moduleExtension;
// LDEBUG("Loading modules from: " << fullModule);
//
// ghoul::filesystem::Directory oldDirectory = FileSys.currentDirectory();
// FileSys.setCurrentDirectory(modulePath);
//
// ghoul::Dictionary moduleDictionary;
// ghoul::lua::loadDictionaryFromFile(fullModule, moduleDictionary);
// std::vector<std::string> keys = moduleDictionary.keys();
// for (const std::string& key : keys) {
// if (!moduleDictionary.hasValue<ghoul::Dictionary>(key)) {
// LERROR("SceneGraphElement '" << key << "' is not a table in module '"
// << fullModule << "'");
// continue;
// }
//
// ghoul::Dictionary element;
// moduleDictionary.getValue(key, element);
//
// element.setValue(constants::scenegraph::keyPathModule, modulePath);
//
// //each element in this new dictionary becomes a scenegraph node.
// SceneGraphNode* node = SceneGraphNode::createFromDictionary(element);
//
// _allNodes.emplace(node->name(), node);
// _nodes.push_back(node);
// }
//
// FileSys.setCurrentDirectory(oldDirectory);
//
// // Print the tree
// //printTree(_root);
//}
SceneGraphNode* Scene::root() const {
return _graph.rootNode();
return _root.get();
}
SceneGraphNode* Scene::sceneGraphNode(const std::string& name) const {
return _graph.sceneGraphNode(name);
auto it = _nodesByName.find(name);
if (it != _nodesByName.end()) {
return it->second;
}
return nullptr;
}
std::vector<SceneGraphNode*> Scene::allSceneGraphNodes() const {
return _graph.nodes();
}
SceneGraph& Scene::sceneGraph() {
return _graph;
const std::vector<SceneGraphNode*>& Scene::allSceneGraphNodes() const {
return _topologicallySortedNodes;
}
void Scene::writePropertyDocumentation(const std::string& filename, const std::string& type, const std::string& sceneFilename) {
@@ -457,7 +287,7 @@ void Scene::writePropertyDocumentation(const std::string& filename, const std::s
file.open(filename);
using properties::Property;
for (SceneGraphNode* node : _graph.nodes()) {
for (SceneGraphNode* node : allSceneGraphNodes()) {
std::vector<Property*> properties = node->propertiesRecursive();
if (!properties.empty()) {
file << node->name() << std::endl;
@@ -547,7 +377,7 @@ void Scene::writePropertyDocumentation(const std::string& filename, const std::s
std::stringstream json;
json << "[";
std::vector<SceneGraphNode*> nodes = _graph.nodes();
std::vector<SceneGraphNode*> nodes = allSceneGraphNodes();
if (!nodes.empty()) {
json << std::accumulate(
std::next(nodes.begin()),
@@ -598,45 +428,6 @@ void Scene::writePropertyDocumentation(const std::string& filename, const std::s
<< "\t<body>\n"
<< "\t<body>\n"
<< "</html>\n";
/*
html << "<html>\n"
<< "\t<head>\n"
<< "\t\t<title>Properties</title>\n"
<< "\t</head>\n"
<< "<body>\n"
<< "<table cellpadding=3 cellspacing=0 border=1>\n"
<< "\t<caption>Properties</caption>\n\n"
<< "\t<thead>\n"
<< "\t\t<tr>\n"
<< "\t\t\t<th>ID</th>\n"
<< "\t\t\t<th>Type</th>\n"
<< "\t\t\t<th>Description</th>\n"
<< "\t\t</tr>\n"
<< "\t</thead>\n"
<< "\t<tbody>\n";
for (SceneGraphNode* node : _graph.nodes()) {
for (properties::Property* p : node->propertiesRecursive()) {
html << "\t\t<tr>\n"
<< "\t\t\t<td>" << p->fullyQualifiedIdentifier() << "</td>\n"
<< "\t\t\t<td>" << p->className() << "</td>\n"
<< "\t\t\t<td>" << p->guiName() << "</td>\n"
<< "\t\t</tr>\n";
}
if (!node->propertiesRecursive().empty()) {
html << "\t<tr><td style=\"line-height: 10px;\" colspan=3></td></tr>\n";
}
}
html << "\t</tbody>\n"
<< "</table>\n"
<< "</html>;";
*/
file << html.str();
}
else
@@ -703,4 +494,8 @@ scripting::LuaLibrary Scene::luaLibrary() {
};
}
Scene::InvalidSceneError::InvalidSceneError(const std::string& error, const std::string& comp)
: ghoul::RuntimeError(error, comp)
{}
} // namespace openspace

View File

@@ -213,9 +213,8 @@ int loadScene(lua_State* L) {
SCRIPT_CHECK_ARGUMENTS("loadScene", L, 1, nArguments);
std::string sceneFile = luaL_checkstring(L, -1);
OsEng.renderEngine().scene()->scheduleLoadSceneFile(sceneFile);
OsEng.scheduleLoadScene(sceneFile);
return 0;
}
@@ -234,22 +233,11 @@ int addSceneGraphNode(lua_State* L) {
return 0;
}
SceneGraphNode* node = SceneGraphNode::createFromDictionary(d);
std::string parent = d.value<std::string>(SceneGraphNode::KeyParentName);
SceneGraphNode* parentNode = OsEng.renderEngine().scene()->sceneGraphNode(parent);
if (!parentNode) {
LERRORC(
"addSceneGraphNode",
errorLocation(L) << "Could not find parent node '" << parent << "'"
);
return 0;
}
node->setParent(parentNode);
node->initialize();
OsEng.renderEngine().scene()->sceneGraph().addSceneGraphNode(node);
SceneLoader loader;
SceneGraphNode* importedNode = loader.importNodeDictionary(*OsEng.renderEngine().scene(), d);
importedNode->initialize();
return 0;
return 1;
}
int removeSceneGraphNode(lua_State* L) {
@@ -257,21 +245,25 @@ int removeSceneGraphNode(lua_State* L) {
int nArguments = lua_gettop(L);
SCRIPT_CHECK_ARGUMENTS("removeSceneGraphNode", L, 1, nArguments);
std::string nodeName = luaL_checkstring(L, -1);
SceneGraphNode* node = OsEng.renderEngine().scene()->sceneGraphNode(nodeName);
if (!node) {
LERRORC(
"removeSceneGraphNode",
errorLocation(L) << "Could not find node '" << nodeName << "'"
);
);
return 0;
}
OsEng.renderEngine().scene()->sceneGraph().removeSceneGraphNode(node);
node->deinitialize();
delete node;
SceneGraphNode* parent = node->parent();
if (!parent) {
LERRORC(
"removeSceneGraphNode",
errorLocation(L) << "Cannot remove root node"
);
return 0;
}
parent->detachChild(*node);
return 1;
}

View File

@@ -1,580 +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/scenegraph.h>
#include <openspace/documentation/documentation.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/interaction/interactionhandler.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/lua/lua_helper.h>
#include <ghoul/misc/onscopeexit.h>
#include <stack>
#include <unordered_map>
#ifdef _MSC_VER
#ifdef OPENSPACE_ENABLE_VLD
#include <vld.h>
#endif
#endif
namespace {
const std::string _loggerCat = "SceneGraph";
const std::string _moduleExtension = ".mod";
const std::string _defaultCommonDirectory = "common";
const std::string _commonModuleToken = "${COMMON_MODULE}";
const std::string KeyPathScene = "ScenePath";
const std::string KeyModules = "Modules";
const std::string KeyCommonFolder = "CommonFolder";
const std::string KeyPathModule = "ModulePath";
}
namespace openspace {
SceneGraph::SceneGraphNodeInternal::~SceneGraphNodeInternal() {
delete node;
}
SceneGraph::SceneGraph()
: _rootNode(nullptr)
{}
SceneGraph::~SceneGraph() {
clear();
}
void SceneGraph::clear() {
// Untested ---abock
for (SceneGraphNodeInternal* n : _nodes)
delete n;
_nodes.clear();
_rootNode = nullptr;
}
bool SceneGraph::loadFromFile(const std::string& sceneDescription) {
clear(); // Move this to a later stage to retain a proper scenegraph when the loading fails ---abock
std::string absSceneFile = absPath(sceneDescription);
// See if scene file exists
using RawPath = ghoul::filesystem::FileSystem::RawPath;
if (!FileSys.fileExists(absSceneFile, RawPath::Yes)) {
LERROR("Could not load scene file '" << absSceneFile << "'. " <<
"File not found");
return false;
}
LINFO("Loading SceneGraph from file '" << absSceneFile << "'");
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);
// Load dictionary
ghoul::Dictionary sceneDictionary;
try {
ghoul::lua::loadDictionaryFromFile(
absSceneFile,
sceneDictionary,
state
);
}
catch (...) {
// @CLEANUP: This is bad to just catch all exceptions! ---abock
return false;
}
std::string sceneDescriptionDirectory = ghoul::filesystem::File(
absSceneFile,
ghoul::filesystem::File::RawPath::Yes
).directoryName();
std::string sceneDirectory(".");
sceneDictionary.getValue(KeyPathScene, sceneDirectory);
// The scene path could either be an absolute or relative path to the description
// paths directory
std::string relativeCandidate = sceneDescriptionDirectory +
ghoul::filesystem::FileSystem::PathSeparator + sceneDirectory;
std::string absoluteCandidate = absPath(sceneDirectory);
if (FileSys.directoryExists(relativeCandidate))
sceneDirectory = relativeCandidate;
else if (FileSys.directoryExists(absoluteCandidate))
sceneDirectory = absoluteCandidate;
else {
LERROR("The '" << KeyPathScene << "' pointed to a "
"path '" << sceneDirectory << "' that did not exist");
return false;
}
ghoul::Dictionary moduleDictionary;
bool success = sceneDictionary.getValue(KeyModules, moduleDictionary);
if (!success)
// There are no modules that are loaded
return true;
// lua_State* state = ghoul::lua::createNewLuaState();
// OsEng.scriptEngine().initializeLuaState(state);
// Above we generated a ghoul::Dictionary from the scene file; now we run the scene
// file again to load any variables defined inside into the state that is passed to
// the modules. This allows us to specify global variables that can then be used
// inside the modules to toggle settings
ghoul::lua::runScriptFile(state, absSceneFile);
// Get the common directory
bool commonFolderSpecified = sceneDictionary.hasKey(KeyCommonFolder);
bool commonFolderCorrectType = sceneDictionary.hasKeyAndValue<std::string>(KeyCommonFolder);
if (commonFolderSpecified) {
if (commonFolderCorrectType) {
std::string commonFolder = sceneDictionary.value<std::string>(KeyCommonFolder);
std::string fullCommonFolder = FileSys.pathByAppendingComponent(
sceneDirectory,
commonFolder
);
if (!FileSys.directoryExists(fullCommonFolder))
LERROR("Specified common folder '" << fullCommonFolder << "' did not exist");
else {
if (!commonFolder.empty()) {
FileSys.registerPathToken(
_commonModuleToken, commonFolder,
ghoul::filesystem::FileSystem::Override::Yes
);
size_t nKeys = moduleDictionary.size();
moduleDictionary.setValue(
std::to_string(nKeys + 1),
commonFolder
);
}
}
}
else
LERROR("Specification for 'common' folder has invalid type");
}
std::vector<std::string> keys = moduleDictionary.keys();
std::map<std::string, std::vector<std::string>> dependencies;
std::map<std::string, std::string> parents;
_rootNode = new SceneGraphNode;
_rootNode->setName(SceneGraphNode::RootNodeName);
SceneGraphNodeInternal* internalRoot = new SceneGraphNodeInternal;
internalRoot->node = _rootNode;
_nodes.push_back(internalRoot);
std::sort(keys.begin(), keys.end());
ghoul::filesystem::Directory oldDirectory = FileSys.currentDirectory();
for (const std::string& key : keys) {
std::string fullModuleName = moduleDictionary.value<std::string>(key);
std::replace(fullModuleName.begin(), fullModuleName.end(), '/', FileSys.PathSeparator);
std::string modulePath = FileSys.pathByAppendingComponent(sceneDirectory, fullModuleName);
std::string moduleName = fullModuleName;
std::string::size_type pos = fullModuleName.find_last_of(FileSys.PathSeparator);
if (pos != std::string::npos)
moduleName = fullModuleName.substr(pos + 1);
if (!FileSys.directoryExists(modulePath)) {
LERROR("Could not load module '" << moduleName << "'. Directory did not exist");
continue;
}
std::string moduleFile = FileSys.pathByAppendingComponent(
modulePath,
moduleName + _moduleExtension
);
struct ModuleInformation {
ghoul::Dictionary dictionary;
std::string moduleFile;
std::string modulePath;
std::string moduleName;
};
std::vector<ModuleInformation> moduleDictionaries;
if (FileSys.fileExists(moduleFile)) {
// We have a module file, so it is a direct include
try {
ghoul::Dictionary moduleDictionary;
ghoul::lua::loadDictionaryFromFile(moduleFile, moduleDictionary, state);
moduleDictionaries.push_back({
moduleDictionary,
moduleFile,
modulePath,
moduleName
});
}
catch (const ghoul::lua::LuaRuntimeException& e) {
LERRORC(e.component, e.message);
continue;
}
}
else {
// If we do not have a module file, we have to include all subdirectories
using ghoul::filesystem::Directory;
using std::string;
std::vector<string> directories = Directory(modulePath).readDirectories();
for (const string& s : directories) {
std::string::size_type pos = s.find_last_of(FileSys.PathSeparator);
if (pos == std::string::npos) {
LERROR("Error parsing subdirectory name '" << s << "'");
continue;
}
string moduleName = s.substr(pos+1);
string submodulePath = s;
string moduleFile = FileSys.pathByAppendingComponent(submodulePath, moduleName) + _moduleExtension;
// string moduleName = s;
if (!FileSys.fileExists(moduleFile)) {
continue;
}
// We have a module file, so it is a direct include
try {
ghoul::Dictionary moduleDictionary;
ghoul::lua::loadDictionaryFromFile(moduleFile, moduleDictionary, state);
moduleDictionaries.push_back({
moduleDictionary,
moduleFile,
submodulePath,
moduleName
});
}
catch (const ghoul::lua::LuaRuntimeException& e) {
LERRORC(e.component, e.message);
continue;
}
}
}
auto addModule = [this, &dependencies, &parents](const ModuleInformation& moduleInformation) {
const ghoul::Dictionary& moduleDictionary = moduleInformation.dictionary;
const std::string& moduleFile = moduleInformation.moduleFile;
const std::string& modulePath = moduleInformation.modulePath;
const std::string& moduleName = moduleInformation.moduleName;
std::vector<std::string> keys = moduleDictionary.keys();
for (const std::string& key : keys) {
if (!moduleDictionary.hasValue<ghoul::Dictionary>(key)) {
LERROR("SceneGraphNode '" << key << "' is not a table in module '"
<< moduleFile << "'");
continue;
}
ghoul::Dictionary element;
std::string nodeName;
std::string parentName;
moduleDictionary.getValue(key, element);
element.setValue(KeyPathModule, modulePath);
element.getValue(SceneGraphNode::KeyName, nodeName);
element.getValue(SceneGraphNode::KeyParentName, parentName);
FileSys.setCurrentDirectory(modulePath);
LDEBUGC("Create from dictionary", "Node name: " << nodeName << " Parent name:" << parentName << " Path: " << modulePath);
SceneGraphNode* node = SceneGraphNode::createFromDictionary(element);
if (node == nullptr) {
LERROR("Error loading SceneGraphNode '" << nodeName << "' in module '" << moduleName << "'");
continue;
}
dependencies[nodeName].push_back(parentName);
parents[nodeName] = parentName;
// Also include loaded dependencies
if (element.hasKey(SceneGraphNode::KeyDependencies)) {
if (element.hasValue<ghoul::Dictionary>(SceneGraphNode::KeyDependencies)) {
ghoul::Dictionary nodeDependencies;
element.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[nodeName].push_back(value);
}
}
else {
LERROR("Dependencies did not have the corrent type");
}
}
SceneGraphNodeInternal* internalNode = new SceneGraphNodeInternal;
internalNode->node = node;
_nodes.push_back(internalNode);
}
};
for (const ModuleInformation& i : moduleDictionaries) {
try {
LINFO("Adding module: " << i.moduleName);
addModule(i);
}
catch (const documentation::SpecificationError& specError) {
LERROR("Error loading module: " << i.moduleName);
LERRORC(specError.component, specError.message);
for (const auto& offense : specError.result.offenses) {
LERRORC(offense.offender, std::to_string(offense.reason));
}
}
}
}
// ghoul::lua::destroyLuaState(state);
FileSys.setCurrentDirectory(oldDirectory);
for (SceneGraphNodeInternal* node : _nodes) {
if (node->node == _rootNode)
continue;
std::string parent = parents[node->node->name()];
SceneGraphNode* parentNode = sceneGraphNode(parent);
if (parentNode == nullptr) {
LERROR("Could not find parent '" << parent << "' for '" << node->node->name() << "'");
continue;
}
node->node->setParent(parentNode);
parentNode->addChild(node->node);
}
// Setup dependencies
for (SceneGraphNodeInternal* node : _nodes) {
std::vector<std::string> nodeDependencies = dependencies[node->node->name()];
for (const std::string& dep : nodeDependencies) {
SceneGraphNodeInternal* n = nodeByName(dep);
if (n == nullptr) {
LERROR("Dependent node '" << dep << "' was not loaded for '" <<node->node->name() << "'");
continue;
}
node->outgoingEdges.push_back(n);
n->incomingEdges.push_back(node);
}
}
std::vector<SceneGraphNodeInternal*> nodesToDelete;
for (SceneGraphNodeInternal* node : _nodes) {
if (!nodeIsDependentOnRoot(node)) {
LERROR("Node '" << node->node->name() << "' has no direct connection to Root.");
nodesToDelete.push_back(node);
}
}
for (SceneGraphNodeInternal* node : nodesToDelete) {
_nodes.erase(std::find(_nodes.begin(), _nodes.end(), node));
delete node;
}
bool s = sortTopologically();
if (!s) {
LERROR("Topological sort failed");
return false;
}
return true;
}
bool SceneGraph::nodeIsDependentOnRoot(SceneGraphNodeInternal* node) {
if (node->node->name() == SceneGraphNode::RootNodeName)
return true;
else {
for (SceneGraphNodeInternal* n : node->outgoingEdges) {
bool dep = nodeIsDependentOnRoot(n);
if (dep)
return true;
}
return false;
}
}
bool SceneGraph::sortTopologically() {
if (_nodes.empty())
return true;
// Only the Root node can have an in-degree of 0
SceneGraphNodeInternal* root = nodeByName(SceneGraphNode::RootNodeName);
ghoul_assert(root != nullptr, "Could not find Root node");
std::stack<SceneGraphNodeInternal*> zeroInDegreeNodes;
zeroInDegreeNodes.push(root);
std::unordered_map<SceneGraphNodeInternal*, size_t> inDegrees;
for (SceneGraphNodeInternal* node : _nodes)
inDegrees[node] = node->outgoingEdges.size();
//inDegrees[node] = node->incomingEdges.size();
_topologicalSortedNodes.clear();
_topologicalSortedNodes.reserve(_nodes.size());
while (!zeroInDegreeNodes.empty()) {
SceneGraphNodeInternal* node = zeroInDegreeNodes.top();
_topologicalSortedNodes.push_back(node->node);
zeroInDegreeNodes.pop();
//for (SceneGraphNodeInternal* n : node->outgoingEdges) {
for (SceneGraphNodeInternal* n : node->incomingEdges) {
inDegrees[n] -= 1;
if (inDegrees[n] == 0)
zeroInDegreeNodes.push(n);
}
}
return true;
}
bool SceneGraph::addSceneGraphNode(SceneGraphNode* node) {
// @TODO rework this ---abock
ghoul_assert(node, "Node must not be nullptr");
SceneGraphNodeInternal* internalNode = new SceneGraphNodeInternal;
internalNode->node = node;
auto it = std::find_if(
_nodes.begin(),
_nodes.end(),
[node](SceneGraphNodeInternal* i) {
return i->node == node->parent();
}
);
if (it == _nodes.end()) {
LERROR("Parent node was not found");
delete internalNode;
return false;
}
(*it)->incomingEdges.push_back(internalNode);
internalNode->outgoingEdges.push_back(*it);
_nodes.push_back(internalNode);
sortTopologically();
return true;
}
bool SceneGraph::removeSceneGraphNode(SceneGraphNode* node) {
// @TODO rework this ---abock
ghoul_assert(node, "Node must not be nullptr");
auto it = std::find_if(
_nodes.begin(),
_nodes.end(),
[node](SceneGraphNodeInternal* i) {
return i->node == node;
}
);
if (it == _nodes.end()) {
LERROR("The node '" << node->name() << "' did not exist in the scenegraph");
return false;
}
// Remove internal node from the list of nodes
//SceneGraphNodeInternal* internalNode = *it;
_nodes.erase(it);
if (OsEng.interactionHandler().focusNode() == node)
OsEng.interactionHandler().setFocusNode(node->parent());
sortTopologically();
#if 0
SceneGraphNodeInternal* parentInternalNode = nodeByName(node->parent()->name());
ghoul_assert(parentInternalNode, "Could not find internal parent node");
// Reparent its children to its parent
for (SceneGraphNode* c : node->children())
c->setParent(node->parent());
// Reset the dependencies accordingly
// VERY untested ---abock
for (SceneGraphNodeInternal* c : internalNode->incomingEdges) {
parentInternalNode->outgoingEdges.insert(parentInternalNode->outgoingEdges.end(), c->outgoingEdges.begin(), c->outgoingEdges.end());
parentInternalNode->incomingEdges.insert(parentInternalNode->incomingEdges.end(), c->incomingEdges.begin(), c->incomingEdges.end());
}
#endif
return true;
}
SceneGraph::SceneGraphNodeInternal* SceneGraph::nodeByName(const std::string& name) {
auto it = std::find_if(
_nodes.begin(),
_nodes.end(),
[name](SceneGraphNodeInternal* node) {
return node->node->name() == name;
}
);
if (it == _nodes.end())
return nullptr;
else
return *it;
}
const std::vector<SceneGraphNode*>& SceneGraph::nodes() const {
return _topologicalSortedNodes;
}
SceneGraphNode* SceneGraph::rootNode() const {
return _rootNode;
}
SceneGraphNode* SceneGraph::sceneGraphNode(const std::string& name) const {
auto it = std::find_if(
_nodes.begin(),
_nodes.end(),
[name](SceneGraphNodeInternal* node) {
return node->node->name() == name;
}
);
if (it != _nodes.end())
return (*it)->node;
else
return nullptr;
}
} // namespace openspace

View File

@@ -65,14 +65,14 @@ const std::string SceneGraphNode::KeyName = "Name";
const std::string SceneGraphNode::KeyParentName = "Parent";
const std::string SceneGraphNode::KeyDependencies = "Dependencies";
SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& dictionary){
std::unique_ptr<SceneGraphNode> SceneGraphNode::createFromDictionary(const ghoul::Dictionary& dictionary){
openspace::documentation::testSpecificationAndThrow(
SceneGraphNode::Documentation(),
dictionary,
"SceneGraphNode"
);
SceneGraphNode* result = new SceneGraphNode;
std::unique_ptr<SceneGraphNode> result = std::make_unique<SceneGraphNode>();
std::string name = dictionary.value<std::string>(KeyName);
result->setName(name);
@@ -87,7 +87,6 @@ SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& di
if (result->_renderable == nullptr) {
LERROR("Failed to create renderable for SceneGraphNode '"
<< result->name() << "'");
delete result;
return nullptr;
}
result->addPropertySubOwner(result->_renderable.get());
@@ -102,7 +101,6 @@ SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& di
if (result->_transform.translation == nullptr) {
LERROR("Failed to create ephemeris for SceneGraphNode '"
<< result->name() << "'");
delete result;
return nullptr;
}
result->addPropertySubOwner(result->_transform.translation.get());
@@ -117,7 +115,6 @@ SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& di
if (result->_transform.rotation == nullptr) {
LERROR("Failed to create rotation for SceneGraphNode '"
<< result->name() << "'");
delete result;
return nullptr;
}
result->addPropertySubOwner(result->_transform.rotation.get());
@@ -132,7 +129,6 @@ SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& di
if (result->_transform.scale == nullptr) {
LERROR("Failed to create scale for SceneGraphNode '"
<< result->name() << "'");
delete result;
return nullptr;
}
result->addPropertySubOwner(result->_transform.scale.get());
@@ -141,12 +137,13 @@ SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& di
LDEBUG("Successfully created SceneGraphNode '"
<< result->name() << "'");
return result;
return std::move(result);
}
SceneGraphNode::SceneGraphNode()
: properties::PropertyOwner("")
, _parent(nullptr)
, _scene(nullptr)
, _transform {
std::make_unique<StaticTranslation>(),
std::make_unique<StaticRotation>(),
@@ -200,6 +197,20 @@ bool SceneGraphNode::deinitialize() {
return true;
}
void SceneGraphNode::traversePreOrder(std::function<void(SceneGraphNode*)> fn) {
fn(this);
for (std::unique_ptr<SceneGraphNode>& child : _children) {
child->traversePreOrder(fn);
}
}
void SceneGraphNode::traversePostOrder(std::function<void(SceneGraphNode*)> fn) {
for (std::unique_ptr<SceneGraphNode>& child : _children) {
child->traversePostOrder(fn);
}
fn(this);
}
void SceneGraphNode::update(const UpdateData& data) {
if (_transform.translation) {
if (data.doPerformanceMeasurement) {
@@ -356,35 +367,134 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) {
// child->render(newData);
}
void SceneGraphNode::setParent(SceneGraphNode& parent, UpdateScene updateScene) {
ghoul_assert(_parent != nullptr, "Node must be attached to a parent");
ghoul_assert(
!updateScene || _scene == parent._scene,
"For the scene to be updated, this object must belong to the same scene as the parent"
);
ghoul_assert(
!updateScene || _parent->_scene == parent._scene,
"Old and new parent cannot belong to separate scenes"
);
// not used anymore @AA
//void SceneGraphNode::addNode(SceneGraphNode* child)
//{
// // add a child node and set this node to be the parent
// child->setParent(this);
// _children.push_back(child);
//}
parent.attachChild(_parent->detachChild(*this, UpdateScene::No), UpdateScene::No);
void SceneGraphNode::setParent(SceneGraphNode* parent) {
_parent = parent;
if (_scene && updateScene) {
_scene->updateDependencies();
}
}
void SceneGraphNode::addChild(SceneGraphNode* child) {
_children.push_back(child);
void SceneGraphNode::attachChild(std::unique_ptr<SceneGraphNode> child, UpdateScene updateScene) {
ghoul_assert(child->parent() == nullptr, "Child may not already have a parent");
child->_parent = this;
if (_scene) {
child->setScene(_scene);
}
_children.push_back(std::move(child));
if (_scene && updateScene) {
_scene->addNode(child.get());
}
}
std::unique_ptr<SceneGraphNode> SceneGraphNode::detachChild(SceneGraphNode& child, UpdateScene updateScene) {
ghoul_assert(child._dependentNodes.empty(), "Nodes cannot depend on a node being detached");
ghoul_assert(child._parent != nullptr, "Node must be attached to a parent");
// Update of deps is deffered to the removal of the node from the scene
clearDependencies(UpdateScene::No);
//not used anymore @AA
//bool SceneGraphNode::abandonChild(SceneGraphNode* child) {
// std::vector < SceneGraphNode* >::iterator it = std::find(_children.begin(), _children.end(), child);
//
// if (it != _children.end()){
// _children.erase(it);
// return true;
// }
//
// return false;
//}
auto iter = std::find_if(
_children.begin(),
_children.end(),
[&child] (const auto& c) {
return &child == c.get();
}
);
std::unique_ptr<SceneGraphNode> c = std::move(*iter);
_children.erase(iter);
if (_scene && updateScene) {
_scene->removeNode(&child);
}
if (_scene) {
setScene(nullptr);
}
return std::move(c);
}
void SceneGraphNode::addDependency(SceneGraphNode& dependency, UpdateScene updateScene) {
dependency._dependentNodes.push_back(this);
_dependencies.push_back(&dependency);
if (_scene && updateScene) {
_scene->updateDependencies();
}
}
void SceneGraphNode::removeDependency(SceneGraphNode& dependency, UpdateScene updateScene) {
dependency._dependentNodes.erase(std::remove_if(
dependency._dependentNodes.begin(),
dependency._dependentNodes.end(),
[this](const auto& d) {
return this == d;
}
), dependency._dependentNodes.end());
_dependencies.erase(std::remove_if(
_dependencies.begin(),
_dependencies.end(),
[&dependency](const auto& d) {
return &dependency == d;
}
), _dependencies.end());
if (_scene && updateScene) {
_scene->updateDependencies();
}
}
void SceneGraphNode::clearDependencies(UpdateScene updateScene) {
for (auto dependency : _dependencies) {
dependency->_dependentNodes.erase(std::remove_if(
dependency->_dependentNodes.begin(),
dependency->_dependentNodes.end(),
[this](const auto& d) {
return this == d;
}
), dependency->_dependentNodes.end());
}
_dependencies.clear();
if (_scene && updateScene) {
_scene->updateDependencies();
}
}
void SceneGraphNode::setDependencies(const std::vector<SceneGraphNode*>& dependencies, UpdateScene updateScene) {
clearDependencies(UpdateScene::No);
_dependencies = dependencies;
for (auto dependency : dependencies) {
dependency->_dependentNodes.push_back(this);
}
if (_scene && updateScene) {
_scene->updateDependencies();
}
}
const std::vector<SceneGraphNode*>& SceneGraphNode::dependencies() const {
return _dependencies;
}
const std::vector<SceneGraphNode*>& SceneGraphNode::dependentNodes() const {
return _dependentNodes;
}
glm::dvec3 SceneGraphNode::position() const
{
@@ -450,15 +560,28 @@ double SceneGraphNode::calculateWorldScale() const {
}
}
SceneGraphNode* SceneGraphNode::parent() const
{
SceneGraphNode* SceneGraphNode::parent() const {
return _parent;
}
const std::vector<SceneGraphNode*>& SceneGraphNode::children() const{
return _children;
Scene* SceneGraphNode::scene() {
return _scene;
}
void SceneGraphNode::setScene(Scene* scene) {
traversePreOrder([scene](SceneGraphNode* node) {
node->_scene = scene;
});
}
std::vector<SceneGraphNode*> SceneGraphNode::children() const {
std::vector<SceneGraphNode*> nodes;
for (auto& child : _children) {
nodes.push_back(child.get());
}
return nodes;
}
// bounding sphere
PowerScaledScalar SceneGraphNode::calculateBoundingSphere(){
// set the bounding sphere to 0.0
_boundingSphere = 0.0;
@@ -489,7 +612,6 @@ PowerScaledScalar SceneGraphNode::calculateBoundingSphere(){
if(renderableBS > _boundingSphere)
_boundingSphere = renderableBS;
}
//LINFO("Bounding Sphere of '" << name() << "': " << _boundingSphere);
return _boundingSphere;
}
@@ -512,7 +634,7 @@ Renderable* SceneGraphNode::renderable() {
return _renderable.get();
}
// private helper methods
/*
bool SceneGraphNode::sphereInsideFrustum(const psc& s_pos, const PowerScaledScalar& s_rad,
const Camera* camera)
{
@@ -543,15 +665,16 @@ bool SceneGraphNode::sphereInsideFrustum(const psc& s_pos, const PowerScaledScal
return false;
}
}
*/
SceneGraphNode* SceneGraphNode::childNode(const std::string& name)
{
if (this->name() == name)
return this;
else
for (SceneGraphNode* it : _children) {
for (std::unique_ptr<SceneGraphNode>& it : _children) {
SceneGraphNode* tmp = it->childNode(name);
if (tmp != nullptr)
if (tmp)
return tmp;
}
return nullptr;

396
src/scene/sceneloader.cpp Normal file
View File

@@ -0,0 +1,396 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* 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/engine/openspaceengine.h>
#include <openspace/scene/sceneloader.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/documentation/verifier.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/onscopeexit.h>
#include <unordered_set>
namespace {
const std::string _loggerCat = "SceneLoader";
const std::string KeyPathScene = "ScenePath";
const std::string KeyModules = "Modules";
const std::string ModuleExtension = ".mod";
const std::string KeyPathModule = "ModulePath";
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";
const std::string KeyCameraPosition = "Position";
const std::string KeyCameraRotation = "Rotation";
}
struct ModuleInformation {
ghoul::Dictionary dictionary;
std::string moduleFile;
std::string modulePath;
std::string moduleName;
};
namespace openspace {
std::unique_ptr<Scene> SceneLoader::loadScene(const std::string& path) {
// Set up lua state.
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 absScenePath = absPath(path);
ghoul::filesystem::File sceneFile(absScenePath);
std::string sceneDirectory = sceneFile.directoryName();
ghoul::Dictionary sceneDictionary;
if (!FileSys.fileExists(absScenePath)) {
throw ghoul::FileNotFoundError(absScenePath);
}
ghoul::lua::loadDictionaryFromFile(absScenePath, sceneDictionary, state);
documentation::testSpecificationAndThrow(Scene::Documentation(), sceneDictionary, "Scene");
std::string relativeSceneDirectory = ".";
sceneDictionary.getValue<std::string>(KeyPathScene, relativeSceneDirectory);
std::string modulesPath = FileSys.absPath(sceneDirectory + FileSys.PathSeparator + relativeSceneDirectory);
ghoul::Dictionary moduleDictionary;
sceneDictionary.getValue(KeyModules, moduleDictionary);
// Above we generated a ghoul::Dictionary from the scene file; now we run the scene
// file again to load any variables defined inside into the state that is passed to
// the modules. This allows us to specify global variables that can then be used
// inside the modules to toggle settings.
ghoul::lua::runScriptFile(state, absScenePath);
std::vector<std::string> keys = moduleDictionary.keys();
ghoul::filesystem::Directory oldDirectory = FileSys.currentDirectory();
std::vector<SceneLoader::LoadedNode> allNodes;
for (const std::string& key : keys) {
std::string fullModuleName = moduleDictionary.value<std::string>(key);
std::replace(fullModuleName.begin(), fullModuleName.end(), '/', FileSys.PathSeparator);
std::string modulePath = FileSys.pathByAppendingComponent(modulesPath, fullModuleName);
std::vector<SceneLoader::LoadedNode> nodes = loadDirectory(modulePath, state);
std::move(nodes.begin(), nodes.end(), std::back_inserter(allNodes));
}
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);
auto& nodeMap = scene->nodesByName();
auto it = nodeMap.find(loadedCamera.parent);
if (it != nodeMap.end()) {
loadedCamera.camera->setParent(it->second);
} else {
LWARNING(
"Could not find the camera parent '" + loadedCamera.parent +
"'. Attaching camera to root node.");
loadedCamera.camera->setParent(scene->root());
}
scene->setCamera(std::move(loadedCamera.camera));
return std::move(scene);
}
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::string focus;
glm::vec3 cameraPosition;
glm::vec4 cameraRotation;
bool readSuccessful = true;
readSuccessful &= cameraDict.getValue(KeyCameraFocus, focus);
readSuccessful &= cameraDict.getValue(KeyCameraPosition, cameraPosition);
readSuccessful &= cameraDict.getValue(KeyCameraRotation, cameraRotation);
std::unique_ptr<Camera> camera = std::make_unique<Camera>();
camera->setPositionVec3(cameraPosition);
camera->setRotation(glm::dquat(
cameraRotation.x, cameraRotation.y, cameraRotation.z, cameraRotation.w));
LoadedCamera loadedCamera(focus, std::move(camera));
if (!readSuccessful) {
throw Scene::InvalidSceneError(
"Position, Rotation and Focus need to be defined for camera dictionary.");
}
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 moduleName = path.substr(pos + 1);
std::string moduleFile = FileSys.pathByAppendingComponent(path, moduleName) + ModuleExtension;
if (FileSys.fileExists(moduleFile)) {
// 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 module file, so it is a direct include.
return loadModule(moduleFile, luaState);
} else {
std::vector<SceneLoader::LoadedNode> allLoadedNodes;
// If we do not have a module file, we have to include all subdirectories.
using ghoul::filesystem::Directory;
using std::string;
std::vector<string> directories = Directory(path).readDirectories();
for (const string& s : directories) {
//std::string submodulePath = FileSys.pathByAppendingComponent(path, s);
std::vector<SceneLoader::LoadedNode> loadedNodes = loadDirectory(s, 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::loadModule(const std::string& path, lua_State* luaState) {
ghoul::Dictionary moduleDictionary;
try {
ghoul::lua::loadDictionaryFromFile(path, moduleDictionary, luaState);
} catch (const ghoul::lua::LuaRuntimeException& e) {
LERRORC(e.component, e.message);
return std::vector<SceneLoader::LoadedNode>();
}
std::vector<SceneLoader::LoadedNode> loadedNodes;
std::vector<std::string> keys = moduleDictionary.keys();
for (const std::string& key : keys) {
ghoul::Dictionary nodeDictionary;
if (!moduleDictionary.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 " << path << ": " << 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(std::move(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(std::move(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

@@ -0,0 +1,53 @@
/*****************************************************************************************
* *
* 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 {
Scene* SceneManager::loadScene(const std::string& path) {
SceneLoader loader;
std::unique_ptr<Scene> scene = loader.loadScene(path);
Scene* s = scene.get();
if (s) {
_scenes.push_back(std::move(scene));
}
return s;
}
void SceneManager::unloadScene(Scene& scene) {
std::remove_if(_scenes.begin(), _scenes.end(), [&scene] (auto& s) {
return s.get() == &scene;
});
}
void SceneManager::unloadAll() {
_scenes.clear();
}
}

View File

@@ -103,6 +103,10 @@ namespace openspace {
_cachedSinMaxFov.isDirty = true;
}
void Camera::setParent(SceneGraphNode* parent) {
_parent = parent;
}
// Relative mutators
void Camera::rotate(Quat rotation) {
std::lock_guard<std::mutex> _lock(_mutex);
@@ -167,6 +171,10 @@ namespace openspace {
return _cachedSinMaxFov.datum;
}
SceneGraphNode * Camera::parent() const {
return _parent;
}
const Camera::Mat4& Camera::viewRotationMatrix() const {
if (_cachedViewRotationMatrix.isDirty) {
_cachedViewRotationMatrix.datum = glm::mat4_cast(glm::inverse((glm::dquat)_rotation));

View File

@@ -0,0 +1,9 @@
return {
{
Name = "ChildAndDependent",
Parent = "NoDependency",
Dependencies = {
"Dependent"
}
}
}

View File

@@ -1,6 +1,6 @@
return {
{
Name = "DirectDependency",
Name = "Child",
Parent = "NoDependency"
}
}

View File

@@ -1,7 +1,8 @@
return {
{
Name = "CircularDependency1",
Parent = "CircularDependency2"
Parent = "Root",
Dependencies = {"CircularDependency2"}
},
{
Name = "CircularDependency2",

View File

@@ -0,0 +1,7 @@
return {
{
Name = "Dependent",
Parent = "Root",
Dependencies = {"NoDependency"}
}
}

View File

@@ -1,6 +1,6 @@
-- Malformed script
return {
ScenePath = ".",
ScenePath = 1337,
Modules = {
}
}

View File

@@ -1,8 +1,6 @@
-- Malformed script
return {
ScenePath = ".",
CommonFolder = 2,
Modules = {
}
Modules = 2
}

View File

@@ -1,6 +1,6 @@
return {
{
Name = "DirectDependency",
Name = "Child",
Parent = "NoDependency"
}
}

View File

@@ -1,7 +1,11 @@
-- Loading an empty common and module dictionary in a different folder
return {
ScenePath = "scene-folder",
CommonFolder = "",
Camera = {
Position = {0.0, 0.0, 0.0},
Rotation = {0.0, 0.0, 0.0, 0.0},
Focus = "Root"
},
Modules = {
}
}

View File

@@ -0,0 +1,12 @@
-- Loading an empty common and module dictionary
return {
ScenePath = ".",
Camera = {
Position = {0.0, 0.0, 0.0},
Rotation = {0.0, 0.0, 0.0, 0.0},
Focus = "Root"
},
Modules = {
}
}

View File

@@ -1,7 +1,11 @@
-- Loading a module without dependencies in a different folder
return {
ScenePath = "scene-folder",
CommonFolder = "common",
Camera = {
Position = {0.0, 0.0, 0.0},
Rotation = {0.0, 0.0, 0.0, 0.0},
Focus = "Root"
},
Modules = {
"no-dependency"
}

View File

@@ -1,7 +1,11 @@
-- Loading a module without dependencies
return {
ScenePath = ".",
CommonFolder = "common",
Camera = {
Position = {0.0, 0.0, 0.0},
Rotation = {0.0, 0.0, 0.0, 0.0},
Focus = "Root"
},
Modules = {
"no-dependency"
}

View File

@@ -1,10 +1,14 @@
-- Loading a module with a direct dependency in a different folder
return {
ScenePath = "scene-folder",
CommonFolder = "common",
Camera = {
Position = {0.0, 0.0, 0.0},
Rotation = {0.0, 0.0, 0.0, 0.0},
Focus = "Root"
},
Modules = {
"no-dependency",
"direct-dependency"
"child"
}
}

View File

@@ -0,0 +1,14 @@
-- Loading a module with a direct dependency
return {
ScenePath = ".",
Camera = {
Position = {0.0, 0.0, 0.0},
Rotation = {0.0, 0.0, 0.0, 0.0},
Focus = "Root"
},
Modules = {
"no-dependency",
"child"
}
}

View File

@@ -0,0 +1,14 @@
-- Multiple Dependencies
return {
ScenePath = ".",
Camera = {
Position = {0.0, 0.0, 0.0},
Rotation = {0.0, 0.0, 0.0, 0.0},
Focus = "Root"
},
Modules = {
"no-dependency",
"dependent"
}
}

View File

@@ -0,0 +1,16 @@
-- Multiple Dependencies
return {
ScenePath = ".",
Camera = {
Position = {0.0, 0.0, 0.0},
Rotation = {0.0, 0.0, 0.0, 0.0},
Focus = "Root"
},
Modules = {
"child",
"child-and-dependent",
"no-dependency",
"dependent"
}
}

View File

@@ -0,0 +1,13 @@
-- Circular Dependencies
return {
ScenePath = ".",
Camera = {
Position = {0.0, 0.0, 0.0},
Rotation = {0.0, 0.0, 0.0, 0.0},
Focus = "Root"
},
Modules = {
"circular-dependency"
}
}

View File

@@ -1,6 +0,0 @@
return {
{
Name = "CommonDependency",
Parent = "Common"
}
}

View File

@@ -1,6 +0,0 @@
return {
{
Name = "Common",
Parent = "Root",
},
}

View File

@@ -1,8 +0,0 @@
-- Malformed script
return {
ScenePath = "foobar",
CommonFolder = "",
Modules = {
}
}

View File

@@ -1,8 +0,0 @@
-- Malformed script
return {
ScenePath = ".",
CommonFolder = "nonexisting",
Modules = {
}
}

View File

@@ -1,9 +0,0 @@
return {
{
Name = "MultipleDependencies",
Parent = "NoDependency",
Dependency = {
"DirectDependency"
}
}
}

View File

@@ -1,6 +0,0 @@
return {
{
Name = "CommonDependency",
Parent = "Common"
}
}

View File

@@ -1,6 +0,0 @@
return {
{
Name = "Common",
Parent = "Root",
},
}

View File

@@ -1,9 +0,0 @@
return {
{
Name = "MultipleDependencies",
Parent = "NoDependency",
Dependency = {
"DirectDependency"
}
}
}

View File

@@ -1,8 +0,0 @@
-- Loading an empty common and module dictionary
return {
ScenePath = ".",
CommonFolder = "",
Modules = {
}
}

View File

@@ -1,8 +0,0 @@
-- Loading an empty module dictionary in a different folder
return {
ScenePath = "scene-folder",
CommonFolder = "common",
Modules = {
}
}

View File

@@ -1,8 +0,0 @@
-- Loading an empty module dictionary
return {
ScenePath = ".",
CommonFolder = "common",
Modules = {
}
}

View File

@@ -1,9 +0,0 @@
-- Loading a module with a dependency on the common module in a different folder
return {
ScenePath = "scene-folder",
CommonFolder = "common",
Modules = {
"common-dependency"
}
}

View File

@@ -1,9 +0,0 @@
-- Loading a module with a dependency on the common module
return {
ScenePath = ".",
CommonFolder = "common",
Modules = {
"common-dependency"
}
}

View File

@@ -1,10 +0,0 @@
-- Loading a module with a direct dependency
return {
ScenePath = ".",
CommonFolder = "common",
Modules = {
"no-dependency",
"direct-dependency"
}
}

View File

@@ -1,11 +0,0 @@
-- Multiple Dependencies in a different folder
return {
ScenePath = "scene-folder",
CommonFolder = "common",
Modules = {
"multiple-dependencies",
"no-dependency",
"direct-dependency"
}
}

View File

@@ -1,11 +0,0 @@
-- Multiple Dependencies
return {
ScenePath = ".",
CommonFolder = "common",
Modules = {
"multiple-dependencies",
"no-dependency",
"direct-dependency"
}
}

View File

@@ -1,9 +0,0 @@
-- Circular Dependencies in a different folder
return {
ScenePath = "scene-folder",
Modules = {
"common",
"circular-dependency"
}
}

View File

@@ -1,9 +0,0 @@
-- Circular Dependencies
return {
ScenePath = ".",
Modules = {
"common",
"circular-dependency"
}
}

View File

@@ -37,7 +37,7 @@
// test files
#include <test_common.inl>
#include <test_spicemanager.inl>
#include <test_scenegraphloader.inl>
#include <test_sceneloader.inl>
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
//#include <test_chunknode.inl>

View File

@@ -1,381 +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 "gtest/gtest.h"
#include <openspace/scene/scenegraphnode.h>
#include <fstream>
class SceneGraphLoaderTest : public testing::Test {};
//TEST_F(SceneGraphLoaderTest, NonExistingFileTest) {
// const std::string file = "NonExistingFile";
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// EXPECT_FALSE(success) << "Unsuccessful loading";
// EXPECT_TRUE(nodes.empty()) << "Empty scenegraph nodes list";
//}
//
//TEST_F(SceneGraphLoaderTest, IllformedFileTest) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/illformed.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// EXPECT_FALSE(success) << "Unsuccessful loading";
// EXPECT_TRUE(nodes.empty()) << "Empty scenegraph nodes list";
//}
//
//TEST_F(SceneGraphLoaderTest, IllformedFileTestWrongCommonFolderType) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/illformedWrongType.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// EXPECT_FALSE(success) << "Unsuccessful loading";
// EXPECT_TRUE(nodes.empty()) << "Empty scenegraph nodes list";
//}
//
//TEST_F(SceneGraphLoaderTest, IllformedFileTestInvalidSceneFolder) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/illformedInvalidScene.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// EXPECT_FALSE(success) << "Unsuccessful loading";
// EXPECT_TRUE(nodes.empty()) << "Empty scenegraph nodes list";
//}
//
//TEST_F(SceneGraphLoaderTest, IllformedFileTestWrongCommonFolder) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/illformedWrongCommon.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// EXPECT_FALSE(success) << "Unsuccessful loading";
// EXPECT_TRUE(nodes.empty()) << "Empty scenegraph nodes list";
//}
//
//TEST_F(SceneGraphLoaderTest, IllformedFileTestNonExistingCommonFolder) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/illformedNonExistingCommon.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// EXPECT_FALSE(success) << "Unsuccessful loading";
// EXPECT_TRUE(nodes.empty()) << "Empty scenegraph nodes list";
//}
//
//TEST_F(SceneGraphLoaderTest, Test00) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test00.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// EXPECT_TRUE(nodes.empty()) << "No scenegraph nodes loaded";
//}
//
//TEST_F(SceneGraphLoaderTest, Test00Location) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test00-location.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// EXPECT_TRUE(nodes.empty()) << "No scenegraph nodes loaded";
//}
//
//TEST_F(SceneGraphLoaderTest, AbsoluteScenePath) {
// const std::string scenePath = absPath("${TEMPORARY}/tmp.scene");
// std::ofstream scene(scenePath.c_str());
//
// scene << "return {" << std::endl <<
// " ScenePath = \"" << absPath("${TESTDIR}/SceneGraphLoaderTest/scene-folder") <<
// "\"," << std::endl <<
// " CommonFolder = \"\"," << std::endl <<
// " Modules = {}}" << std::endl;
// scene.close();
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(scenePath, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// EXPECT_TRUE(nodes.empty()) << "No scenegraph nodes loaded";
//}
//
//TEST_F(SceneGraphLoaderTest, Test01) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test01.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// ASSERT_TRUE(nodes.size() == 1) << "Correct number of nodes";
// EXPECT_TRUE(nodes[0]->name() == "Common") << "Correct node loaded";
//}
//
//TEST_F(SceneGraphLoaderTest, Test01Location) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test01-location.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// ASSERT_TRUE(nodes.size() == 1) << "Correct number of nodes";
// EXPECT_TRUE(nodes[0]->name() == "Common") << "Correct node loaded";
//}
//
//TEST_F(SceneGraphLoaderTest, Test02) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test02.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// ASSERT_TRUE(nodes.size() == 2) << "Correct number of nodes";
// bool found = false;
// for (openspace::SceneGraphNode* n : nodes)
// if (n->name() == "NoDependency")
// found = true;
//
// EXPECT_TRUE(found) << "Correct node loaded";
//}
//
//TEST_F(SceneGraphLoaderTest, Test02Location) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test02-location.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// ASSERT_TRUE(nodes.size() == 2) << "Correct number of nodes";
// bool found = false;
// for (openspace::SceneGraphNode* n : nodes)
// if (n->name() == "NoDependency")
// found = true;
//
// EXPECT_TRUE(found) << "Correct node loaded";
//}
//
//TEST_F(SceneGraphLoaderTest, Test03) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test03.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// ASSERT_TRUE(nodes.size() == 2) << "Correct number of nodes";
// bool found = false;
// for (openspace::SceneGraphNode* n : nodes)
// if (n->name() == "CommonDependency")
// found = true;
//
// EXPECT_TRUE(found) << "Correct node loaded";
//}
//
//TEST_F(SceneGraphLoaderTest, Test03Location) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test03-location.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// ASSERT_TRUE(nodes.size() == 2) << "Correct number of nodes";
// bool found = false;
// for (openspace::SceneGraphNode* n : nodes)
// if (n->name() == "CommonDependency")
// found = true;
//
// EXPECT_TRUE(found) << "Correct node loaded";
//}
//
//TEST_F(SceneGraphLoaderTest, Test04) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test04.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// ASSERT_TRUE(nodes.size() == 3) << "Correct number of nodes";
// bool found = false;
// for (openspace::SceneGraphNode* n : nodes)
// if (n->name() == "DirectDependency")
// found = true;
//
// EXPECT_TRUE(found) << "Correct node loaded";
//}
//
//TEST_F(SceneGraphLoaderTest, Test04Location) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test04-location.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// ASSERT_TRUE(nodes.size() == 3) << "Correct number of nodes";
// bool found = false;
// for (openspace::SceneGraphNode* n : nodes)
// if (n->name() == "DirectDependency")
// found = true;
//
// EXPECT_TRUE(found) << "Correct node loaded";
//}
//
//TEST_F(SceneGraphLoaderTest, Test05) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test05.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// ASSERT_TRUE(nodes.size() == 4) << "Correct number of nodes";
// bool found = false;
// for (openspace::SceneGraphNode* n : nodes)
// if (n->name() == "MultipleDependencies")
// found = true;
//
// EXPECT_TRUE(found) << "Correct node loaded";
//}
//
//TEST_F(SceneGraphLoaderTest, Test05Location) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test05-location.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// ASSERT_TRUE(nodes.size() == 4) << "Correct number of nodes";
// bool found = false;
// for (openspace::SceneGraphNode* n : nodes)
// if (n->name() == "MultipleDependencies")
// found = true;
//
// EXPECT_TRUE(found) << "Correct node loaded";
//}
//
//TEST_F(SceneGraphLoaderTest, Test06) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test06.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_FALSE(success) << "Successful loading";
// ASSERT_TRUE(nodes.empty()) << "Correct number of nodes";
//}
//
//TEST_F(SceneGraphLoaderTest, Test06Location) {
// const std::string file = absPath("${TESTDIR}/SceneGraphLoaderTest/test06-location.scene");
//
// std::vector<openspace::SceneGraphNode*> nodes;
// bool success = openspace::SceneGraphLoader::load(file, nodes);
//
// ASSERT_TRUE(success) << "Successful loading";
// ASSERT_TRUE(nodes.size() == 4) << "Correct number of nodes";
// bool found = false;
// for (openspace::SceneGraphNode* n : nodes)
// if (n->name() == "MultipleDependencies")
// found = true;
//
// EXPECT_TRUE(found) << "No scenegraph nodes loaded";
//}
//
////
////
////
////TEST_F(SceneGraphTest, SceneGraphNode) {
////
//// openspace::SceneGraphNode *node =
//// openspace::SceneGraphNode::createFromDictionary(ghoul::Dictionary());
////
//// // Should not have a renderable and position should be 0,0,0,0 (undefined).
//// EXPECT_EQ(nullptr, node->renderable());
//// EXPECT_EQ(openspace::psc(), node->position());
////
//// delete node;
//// ghoul::Dictionary nodeDictionary;
////
//// ghoul::Dictionary positionDictionary;
//// ghoul::Dictionary positionPositionArrayDictionary;
////
//// ghoul::Dictionary renderableDictionary;
////
//// renderableDictionary.setValue("Type", std::string("RenderablePlanet"));
////
//// positionPositionArrayDictionary.setValue("1", 1.0);
//// positionPositionArrayDictionary.setValue("2", 1.0);
//// positionPositionArrayDictionary.setValue("3", 1.0);
//// positionPositionArrayDictionary.setValue("4", 1.0);
////
//// positionDictionary.setValue("Type", std::string("Static"));
//// positionDictionary.setValue("Position", positionPositionArrayDictionary);
////
//// nodeDictionary.setValue("Position", positionDictionary);
//// nodeDictionary.setValue("Renderable", renderableDictionary);
////
//// node =
//// openspace::SceneGraphNode::createFromDictionary(nodeDictionary);
////
//// // This node should have a renderable (probably no good values but an existing one)
//// EXPECT_TRUE(node->renderable());
////
//// // position should be initialized
//// EXPECT_EQ(openspace::psc(1.0,1.0,1.0,1.0), node->position());
////
//// delete node;
////}
////
////TEST_F(SceneGraphTest, Loading) {
////
////
//// // Should not successfully load a non existing scenegraph
//// EXPECT_FALSE(_scenegraph->loadScene(absPath("${TESTDIR}/ScenegraphTestNonExisting"), absPath("${TESTDIR}")));
////
//// // Existing scenegraph should load
//// EXPECT_TRUE(_scenegraph->loadScene(absPath("${TESTDIR}/ScenegraphTest"), absPath("${TESTDIR}")));
//// // TODO need to check for correctness
////
//// // This loading should fail regardless of existing or not since the
//// // scenegraph is already loaded
//// EXPECT_FALSE(_scenegraph->loadScene(absPath("${TESTDIR}/ScenegraphTest"), absPath("${TESTDIR}")));
////}
////
////TEST_F(SceneGraphTest, Reinitializing) {
////
//// // Existing scenegraph should load
//// EXPECT_TRUE(_scenegraph->loadScene(absPath("${TESTDIR}/ScenegraphTest"), absPath("${TESTDIR}")));
////
//// _scenegraph->deinitialize();
////
//// // Existing scenegraph should load
//// EXPECT_TRUE(_scenegraph->loadScene(absPath("${TESTDIR}/ScenegraphTest"), absPath("${TESTDIR}")));
//// // TODO need to check for correctness
////}
//

265
tests/test_sceneloader.inl Normal file
View File

@@ -0,0 +1,265 @@
/*****************************************************************************************
* *
* 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 "gtest/gtest.h"
#include <openspace/scene/sceneloader.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/documentation/documentation.h>
#include <ghoul/misc/dictionaryluaformatter.h>
#include <ghoul/lua/lua_helper.h>
#include <fstream>
//class SceneLoaderTest : public testing::Test {};
TEST(SceneLoaderTest, NonExistingFileTest) {
const std::string file = absPath("NonExistingFile");
openspace::SceneLoader loader;
EXPECT_THROW(loader.loadScene(file), ghoul::FileNotFoundError);
}
TEST(SceneLoaderTest, IllformedFileTest) {
const std::string file = absPath("${TESTDIR}/SceneLoaderTest/illformed.scene");
openspace::SceneLoader loader;
EXPECT_THROW(loader.loadScene(file), ghoul::lua::LuaRuntimeException);
}
TEST(SceneLoaderTest, IllformedFileTestInvalidSceneFolder) {
const std::string file = absPath("${TESTDIR}/SceneLoaderTest/illformedInvalidScene.scene");
openspace::SceneLoader loader;
EXPECT_THROW(loader.loadScene(file), openspace::documentation::SpecificationError);
}
TEST(SceneLoaderTest, IllformedFileTestWrongType) {
const std::string file = absPath("${TESTDIR}/SceneLoaderTest/illformedWrongType.scene");
openspace::SceneLoader loader;
EXPECT_THROW(loader.loadScene(file), openspace::documentation::SpecificationError);
}
TEST(SceneLoaderTest, AbsoluteScenePath) {
const std::string scenePath = absPath("${TEMPORARY}/tmp.scene");
std::ofstream sceneFile(scenePath.c_str());
ghoul::DictionaryLuaFormatter formatter;
ghoul::Dictionary sceneFileDictionary;
ghoul::Dictionary cameraDictionary;
cameraDictionary.setValue<glm::vec3>("Position", glm::vec3(0.0));
cameraDictionary.setValue<glm::vec4>("Rotation", glm::vec4(0.0));
cameraDictionary.setValue<std::string>("Focus", "Root");
sceneFileDictionary.setValue<std::string>("ScenePath", absPath("${TESTDIR}/SceneLoaderTest/scene-folder"));
sceneFileDictionary.setValue<ghoul::Dictionary>("Modules", ghoul::Dictionary());
sceneFileDictionary.setValue<ghoul::Dictionary>("Camera", cameraDictionary);
sceneFile << "return " << formatter.format(sceneFileDictionary);
sceneFile.close();
openspace::SceneLoader loader;
std::unique_ptr<openspace::Scene> scene = loader.loadScene(scenePath);
ASSERT_NE(scene, nullptr) << "loadScene returned nullptr";
std::vector<openspace::SceneGraphNode*> nodes = scene->allSceneGraphNodes();
EXPECT_EQ(nodes.size(), 1) << "Expected scene to consist of one root node";
}
TEST(SceneLoaderTest, Test00) {
const std::string file = absPath("${TESTDIR}/SceneLoaderTest/test00.scene");
openspace::SceneLoader loader;
std::unique_ptr<openspace::Scene> scene = loader.loadScene(file);
ASSERT_NE(scene, nullptr) << "loadScene returned nullptr";
std::vector<openspace::SceneGraphNode*> nodes = scene->allSceneGraphNodes();
EXPECT_EQ(nodes.size(), 1) << "Expected scene to consist of one root node";
}
TEST(SceneLoaderTest, Test00Location) {
const std::string file = absPath("${TESTDIR}/SceneLoaderTest/test00-location.scene");
openspace::SceneLoader loader;
std::unique_ptr<openspace::Scene> scene = loader.loadScene(file);
ASSERT_NE(scene, nullptr) << "loadScene returned nullptr";
std::vector<openspace::SceneGraphNode*> nodes = scene->allSceneGraphNodes();
EXPECT_EQ(nodes.size(), 1) << "Expected scene to consist of one root node";
}
TEST(SceneLoaderTest, Test01) {
const std::string file = absPath("${TESTDIR}/SceneLoaderTest/test01.scene");
openspace::SceneLoader loader;
std::unique_ptr<openspace::Scene> scene = loader.loadScene(file);
ASSERT_NE(scene, nullptr) << "loadScene returned nullptr";
std::vector<openspace::SceneGraphNode*> nodes = scene->allSceneGraphNodes();
EXPECT_EQ(nodes.size(), 2) << "Expected scene to consist of two nodes";
std::map<std::string, openspace::SceneGraphNode*> nodesByName = scene->nodesByName();
EXPECT_EQ(nodesByName.size(), 2) << "Expected scene to consist of two nodes";
EXPECT_EQ(nodesByName["Root"]->name(), "Root");
EXPECT_EQ(nodesByName["NoDependency"]->name(), "NoDependency");
EXPECT_EQ(nodesByName["NoDependency"]->parent(), nodesByName["Root"]);
}
TEST(SceneLoaderTest, Test01Location) {
const std::string file = absPath("${TESTDIR}/SceneLoaderTest/test01-location.scene");
openspace::SceneLoader loader;
std::unique_ptr<openspace::Scene> scene = loader.loadScene(file);
ASSERT_NE(scene, nullptr) << "loadScene returned nullptr";
std::vector<openspace::SceneGraphNode*> nodes = scene->allSceneGraphNodes();
EXPECT_EQ(nodes.size(), 2) << "Expected scene to consist of two nodes";
std::map<std::string, openspace::SceneGraphNode*> nodesByName = scene->nodesByName();
EXPECT_EQ(nodesByName.size(), 2) << "Expected scene to consist of two nodes";
EXPECT_EQ(nodesByName["Root"]->name(), "Root");
EXPECT_EQ(nodesByName["NoDependency"]->name(), "NoDependency");
EXPECT_EQ(nodesByName["NoDependency"]->parent(), nodesByName["Root"]);
}
TEST(SceneLoaderTest, Test02) {
const std::string file = absPath("${TESTDIR}/SceneLoaderTest/test02.scene");
openspace::SceneLoader loader;
std::unique_ptr<openspace::Scene> scene = loader.loadScene(file);
ASSERT_NE(scene, nullptr) << "loadScene returned nullptr";
std::vector<openspace::SceneGraphNode*> nodes = scene->allSceneGraphNodes();
EXPECT_EQ(nodes.size(), 3) << "Expected scene to consist of two nodes";
std::map<std::string, openspace::SceneGraphNode*> nodesByName = scene->nodesByName();
EXPECT_EQ(nodesByName.size(), 3) << "Expected scene to consist of two nodes";
EXPECT_EQ(nodesByName["Root"]->name(), "Root");
EXPECT_EQ(nodesByName["NoDependency"]->name(), "NoDependency");
EXPECT_EQ(nodesByName["NoDependency"]->parent(), nodesByName["Root"]);
EXPECT_EQ(nodesByName["Child"]->parent(), nodesByName["NoDependency"]);
EXPECT_EQ(nodesByName["Root"]->dependencies().size(), 0);
EXPECT_EQ(nodesByName["NoDependency"]->dependencies().size(), 0);
EXPECT_EQ(nodesByName["Child"]->dependencies().size(), 0);
}
TEST(SceneLoaderTest, Test02Location) {
const std::string file = absPath("${TESTDIR}/SceneLoaderTest/test02-location.scene");
openspace::SceneLoader loader;
std::unique_ptr<openspace::Scene> scene = loader.loadScene(file);
ASSERT_NE(scene, nullptr) << "loadScene returned nullptr";
std::vector<openspace::SceneGraphNode*> nodes = scene->allSceneGraphNodes();
EXPECT_EQ(nodes.size(), 3) << "Expected scene to consist of three nodes";
std::map<std::string, openspace::SceneGraphNode*> nodesByName = scene->nodesByName();
EXPECT_EQ(nodesByName.size(), 3) << "Expected scene to consist of three nodes";
EXPECT_EQ(nodesByName["Root"]->name(), "Root");
EXPECT_EQ(nodesByName["NoDependency"]->name(), "NoDependency");
EXPECT_EQ(nodesByName["Child"]->name(), "Child");
EXPECT_EQ(nodesByName["NoDependency"]->parent(), nodesByName["Root"]);
EXPECT_EQ(nodesByName["Child"]->parent(), nodesByName["NoDependency"]);
EXPECT_EQ(nodesByName["Root"]->dependencies().size(), 0);
EXPECT_EQ(nodesByName["NoDependency"]->dependencies().size(), 0);
EXPECT_EQ(nodesByName["Child"]->dependencies().size(), 0);
}
TEST(SceneLoaderTest, Test03) {
const std::string file = absPath("${TESTDIR}/SceneLoaderTest/test03.scene");
openspace::SceneLoader loader;
std::unique_ptr<openspace::Scene> scene = loader.loadScene(file);
ASSERT_NE(scene, nullptr) << "loadScene returned nullptr";
std::vector<openspace::SceneGraphNode*> nodes = scene->allSceneGraphNodes();
EXPECT_EQ(nodes.size(), 3) << "Expected scene to consist of three nodes";
std::map<std::string, openspace::SceneGraphNode*> nodesByName = scene->nodesByName();
EXPECT_EQ(nodesByName.size(), 3) << "Expected scene to consist of three nodes";
EXPECT_EQ(nodesByName["Root"]->name(), "Root");
EXPECT_EQ(nodesByName["NoDependency"]->name(), "NoDependency");
EXPECT_EQ(nodesByName["Dependent"]->name(), "Dependent");
EXPECT_EQ(nodesByName["NoDependency"]->parent(), nodesByName["Root"]);
EXPECT_EQ(nodesByName["Dependent"]->parent(), nodesByName["Root"]);
EXPECT_EQ(nodesByName["Root"]->dependencies().size(), 0);
EXPECT_EQ(nodesByName["NoDependency"]->dependencies().size(), 0);
EXPECT_EQ(nodesByName["Dependent"]->dependencies().size(), 1);
EXPECT_EQ(nodesByName["Dependent"]->dependencies()[0], nodesByName["NoDependency"]);
}
TEST(SceneLoaderTest, Test04) {
const std::string file = absPath("${TESTDIR}/SceneLoaderTest/test04.scene");
openspace::SceneLoader loader;
std::unique_ptr<openspace::Scene> scene = loader.loadScene(file);
ASSERT_NE(scene, nullptr) << "loadScene returned nullptr";
std::vector<openspace::SceneGraphNode*> nodes = scene->allSceneGraphNodes();
EXPECT_EQ(nodes.size(), 5) << "Expected scene to consist of five nodes";
std::map<std::string, openspace::SceneGraphNode*> nodesByName = scene->nodesByName();
EXPECT_EQ(nodesByName.size(), 5) << "Expected scene to consist of five nodes";
EXPECT_EQ(nodesByName["Root"]->name(), "Root");
EXPECT_EQ(nodesByName["NoDependency"]->name(), "NoDependency");
EXPECT_EQ(nodesByName["Dependent"]->name(), "Dependent");
EXPECT_EQ(nodesByName["ChildAndDependent"]->name(), "ChildAndDependent");
EXPECT_EQ(nodesByName["NoDependency"]->parent(), nodesByName["Root"]);
EXPECT_EQ(nodesByName["Child"]->parent(), nodesByName["NoDependency"]);
EXPECT_EQ(nodesByName["Dependent"]->parent(), nodesByName["Root"]);
EXPECT_EQ(nodesByName["ChildAndDependent"]->parent(), nodesByName["NoDependency"]);
EXPECT_EQ(nodesByName["Root"]->dependencies().size(), 0);
EXPECT_EQ(nodesByName["NoDependency"]->dependencies().size(), 0);
EXPECT_EQ(nodesByName["Dependent"]->dependencies().size(), 1);
EXPECT_EQ(nodesByName["Dependent"]->dependencies()[0], nodesByName["NoDependency"]);
EXPECT_EQ(nodesByName["ChildAndDependent"]->dependencies().size(), 1);
EXPECT_EQ(nodesByName["ChildAndDependent"]->dependencies()[0], nodesByName["Dependent"]);
}
TEST(SceneLoaderTest, Test05) {
const std::string file = absPath("${TESTDIR}/SceneLoaderTest/test05.scene");
openspace::SceneLoader loader;
std::unique_ptr<openspace::Scene> scene = loader.loadScene(file);
std::vector<openspace::SceneGraphNode*> nodes = scene->allSceneGraphNodes();
EXPECT_EQ(nodes.size(), 1);
// TODO: Add more tests regarding circular deps.
}