Refactor scene graph: Move scene loading to separate class.

This commit is contained in:
Emil Axelsson
2016-12-15 10:06:30 +01:00
parent 0ad004bdc9
commit 4751ce36c4
66 changed files with 1551 additions and 2209 deletions

View File

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

View File

@@ -52,6 +52,7 @@ class ModuleEngine;
class WindowWrapper;
class SettingsEngine;
class TimeManager;
class SceneManager;
class SyncEngine;
class ParallelConnection;
@@ -76,6 +77,7 @@ public:
void setMaster(bool master);
double runTime();
void setRunTime(double t);
void loadScene(const std::string& scenePath);
// Guaranteed to return a valid pointer
ConfigurationManager& configurationManager();
@@ -112,6 +114,7 @@ public:
void externalControlCallback(const char* receivedChars, int size, int clientId);
void encode();
void decode();
void scheduleLoadScene(const std::string& scenePath);
void enableBarrier();
void disableBarrier();
@@ -145,6 +148,7 @@ private:
std::unique_ptr<ConfigurationManager> _configurationManager;
std::unique_ptr<interaction::InteractionHandler> _interactionHandler;
std::unique_ptr<RenderEngine> _renderEngine;
std::unique_ptr<SceneManager> _sceneManager;
std::unique_ptr<scripting::ScriptEngine> _scriptEngine;
std::unique_ptr<scripting::ScriptScheduler> _scriptScheduler;
std::unique_ptr<NetworkEngine> _networkEngine;
@@ -165,6 +169,9 @@ private:
// Others
std::unique_ptr<properties::PropertyOwner> _globalPropertyNamespace;
bool _switchScene;
std::string _scenePath;
bool _isMaster;
double _runTime;

View File

@@ -85,6 +85,11 @@ public:
*/
void removeSyncable(Syncable* syncable);
/**
* Remove multiple Syncables from being synchronized over the SGCT cluster
*/
void removeSyncables(const std::vector<Syncable*>& syncables);
private:
/**

View File

@@ -144,7 +144,6 @@ private:
// Properties
properties::StringProperty _origin;
properties::StringProperty _coordinateSystem;
properties::BoolProperty _rotationalFriction;
properties::BoolProperty _horizontalFriction;

View File

@@ -53,8 +53,8 @@ class PerformanceManager;
// Forward declare to minimize dependencies
class Camera;
class SyncBuffer;
class Scene;
class SceneManager;
class Renderer;
class RaycasterManager;
class ScreenLog;
@@ -79,13 +79,14 @@ public:
static const std::vector<FrametimeType> FrametimeTypes;
RenderEngine();
~RenderEngine();
~RenderEngine() = default;
bool initialize();
bool deinitialize();
void setSceneGraph(Scene* sceneGraph);
void setScene(Scene* scene);
Scene* scene();
void updateScene();
Camera* camera() const;
Renderer* renderer() const;
@@ -95,7 +96,7 @@ public:
// sgct wrapped functions
bool initializeGL();
void updateSceneGraph();
void updateShaderPrograms();
void updateFade();
void updateRenderer();
@@ -153,6 +154,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);
@@ -174,9 +180,6 @@ public:
*/
static scripting::LuaLibrary luaLibrary();
// This is a temporary method to change the origin of the coordinate system ---abock
void changeViewPoint(std::string origin);
// Temporary fade functionality
void startFading(int direction, float fadeDuration);
@@ -193,9 +196,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

@@ -35,8 +35,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>
#include <ghoul/misc/dictionary.h>
@@ -48,28 +46,48 @@ 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();
/*
* Clean up everything
*/
bool deinitialize();
void initialize();
/*
* Load the scenegraph from the provided folder
*/
void scheduleLoadSceneFile(const std::string& sceneDescriptionFilePath);
void clearSceneGraph();
//void scheduleLoadSceneFile(const std::string& sceneDescriptionFilePath);
void clear();
void loadModule(const std::string& modulePath);
/*
* Set the root node of the scene
*/
void setRoot(std::unique_ptr<SceneGraphNode> root);
/*
* Set the root node of the scene
*/
void setCamera(std::unique_ptr<Camera> camera);
/**
* Return the camera
*/
Camera* camera() const;
/*
* Updates all SceneGraphNodes relative positions
*/
@@ -96,13 +114,20 @@ public:
*/
SceneGraphNode* sceneGraphNode(const std::string& name) const;
std::vector<SceneGraphNode*> allSceneGraphNodes() const;
void addNode(SceneGraphNode* node, UpdateDependencies updateDeps = UpdateDependencies::Yes);
SceneGraph& sceneGraph();
void removeNode(SceneGraphNode* node, UpdateDependencies updateDeps = UpdateDependencies::Yes);
void updateDependencies();
void sortTopologically();
const std::vector<SceneGraphNode*>& allSceneGraphNodes() const;
const std::map<std::string, SceneGraphNode*>& nodesByName() const;
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
@@ -115,39 +140,16 @@ public:
static documentation::Documentation Documentation();
private:
bool loadSceneInternal(const std::string& sceneDescriptionFilePath);
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;
private:
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

@@ -48,6 +48,8 @@ namespace openspace {
class SceneGraphNode : public properties::PropertyOwner {
public:
using UpdateScene = ghoul::Boolean;
struct PerformanceRecord {
long long renderTime; // time in ns
long long updateTimeRenderable; // time in ns
@@ -64,21 +66,33 @@ 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;
@@ -89,7 +103,7 @@ public:
double worldScale() const;
SceneGraphNode* parent() const;
const std::vector<SceneGraphNode*>& children() const;
std::vector<SceneGraphNode*> children() const;
PowerScaledScalar calculateBoundingSphere();
PowerScaledScalar boundingSphere() const;
@@ -105,14 +119,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,92 @@
/*****************************************************************************************
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___SCENELOADER___H__
#define __OPENSPACE_CORE___SCENELOADER___H__
#include <memory>
#include <string>
#include <ghoul/misc/dictionary.h>
#include <ghoul/lua/ghoul_lua.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/camera.h>
namespace openspace {
class Scene;
class SceneLoader {
public:
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;
};
SceneLoader() = default;
~SceneLoader() = default;
std::unique_ptr<Scene> loadScene(const std::string& path);
std::vector<SceneGraphNode*> importDirectory(Scene& scene, const std::string& directory);
SceneGraphNode* importNodeDictionary(Scene& scene, const ghoul::Dictionary& dictionary);
private:
SceneLoader::LoadedNode loadNode(const ghoul::Dictionary& dictionary);
std::vector<SceneLoader::LoadedNode> loadModule(const std::string& path, lua_State* luaState);
std::vector<SceneLoader::LoadedNode> loadDirectory(const std::string& path, lua_State* luaState);
SceneLoader::LoadedCamera loadCamera(const ghoul::Dictionary& dictionary);
std::vector<SceneGraphNode*> addLoadedNodes(Scene& scene, std::vector<SceneLoader::LoadedNode> nodes);
};
}
#endif // __OPENSPACE_CORE___SCENELOADER___H__

View File

@@ -21,55 +21,27 @@
* 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);
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 != nullptr && newParent != nullptr) {
thisNode->setParent(*newParent);
}
}
const GLfloat vertex_data[] = { // square of two triangles drawn within fov in target coordinates

View File

@@ -80,7 +80,7 @@ Documentation RenderablePlanetProjection::Documentation() {
},
{
keyGeometry,
new ReferencingVerifier("base_geometry_planet"),
new ReferencingVerifier("space_geometry_planet"),
"The geometry that is used for rendering this planet.",
Optional::No
},
@@ -127,7 +127,7 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary&
documentation::testSpecificationAndThrow(
Documentation(),
dictionary,
"RenderablePlanetProject"
"RenderablePlanetProjection"
);
std::string name;

View File

@@ -127,7 +127,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
@@ -269,7 +270,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

@@ -47,7 +47,7 @@
#include <openspace/scripting/scriptengine.h>
#include <openspace/scripting/scriptscheduler.h>
#include <openspace/scene/translation.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenemanager.h>
#include <openspace/util/factorymanager.h>
#include <openspace/util/time.h>
#include <openspace/util/timemanager.h>
@@ -121,16 +121,20 @@ namespace {
namespace openspace {
namespace properties {
class Property;
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)
@@ -149,6 +153,8 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName,
, _parallelConnection(new ParallelConnection)
, _windowWrapper(std::move(windowWrapper))
, _globalPropertyNamespace(new properties::PropertyOwner)
, _switchScene(false)
, _scenePath("")
, _isMaster(false)
, _runTime(0.0)
, _isInShutdownMode(false)
@@ -190,6 +196,11 @@ OpenSpaceEngine::~OpenSpaceEngine() {
#ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED
_gui->deinitializeGL();
#endif
_renderEngine->setScene(nullptr);
_renderEngine->setCamera(nullptr);
_sceneManager = nullptr;
_interactionHandler->deinitialize();
_renderEngine->deinitialize();
@@ -217,12 +228,12 @@ OpenSpaceEngine& OpenSpaceEngine::ref() {
}
bool OpenSpaceEngine::create(int argc, char** argv,
std::unique_ptr<WindowWrapper> windowWrapper,
std::vector<std::string>& sgctArguments)
std::unique_ptr<WindowWrapper> windowWrapper,
std::vector<std::string>& sgctArguments)
{
ghoul_assert(!_engine, "OpenSpaceEngine was already created");
ghoul_assert(windowWrapper != nullptr, "No Window Wrapper was provided");
ghoul::initialize();
// Initialize the LogManager and add the console log as this will be used every time
@@ -323,13 +334,13 @@ bool OpenSpaceEngine::create(int argc, char** argv,
"${CACHE}",
cacheFolder,
ghoul::filesystem::FileSystem::Override::Yes
);
);
}
// 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 << " (" << OPENSPACE_VERSION_STRING << ")");
@@ -488,33 +499,123 @@ bool OpenSpaceEngine::initialize() {
// Load a light and a monospaced font
loadFonts();
// Initialize the Scene
Scene* sceneGraph = new Scene;
sceneGraph->initialize();
std::string scenePath = "";
configurationManager().getValue(ConfigurationManager::KeyConfigScene, scenePath);
sceneGraph->scheduleLoadSceneFile(scenePath);
// Initialize the RenderEngine
_renderEngine->setSceneGraph(sceneGraph);
_renderEngine->initialize();
_renderEngine->setGlobalBlackOutFactor(0.0);
_renderEngine->startFading(1, 3.0);
scheduleLoadScene(scenePath);
LINFO("Finished initializing");
return true;
}
void OpenSpaceEngine::scheduleLoadScene(const std::string& scenePath) {
_switchScene = true;
_scenePath = scenePath;
}
void OpenSpaceEngine::loadScene(const std::string& scenePath) {
windowWrapper().setSynchronization(false);
OnExit(
[this]() { windowWrapper().setSynchronization(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->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;
bool hasType = configurationManager().getValue(KeyboardShortcutsType, type);
bool hasFile = configurationManager().getValue(KeyboardShortcutsFile, file);
if (hasType && hasFile) {
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;
hasType = configurationManager().hasKey(KeyPropertyDocumentationType);
hasFile = 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);
scene->writePropertyDocumentation(propertyDocumentationFile, propertyDocumentationType, scenePath);
}
#ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED
LINFO("Initializing GUI");
_gui->initialize();
_gui->_globalProperty.setSource(
[&]() {
[&]() {
std::vector<properties::PropertyOwner*> res = {
_settingsEngine.get(),
_interactionHandler.get(),
@@ -548,14 +649,14 @@ bool OpenSpaceEngine::initialize() {
groups.end(),
std::back_inserter(res),
[](const auto& val) {
return val.second.get();
return val.second.get();
}
);
return res;
}
);
#endif
#endif
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
@@ -565,9 +666,6 @@ bool OpenSpaceEngine::initialize() {
_syncEngine->addSyncables(Time::ref().getSyncables());
_syncEngine->addSyncables(_renderEngine->getSyncables());
_syncEngine->addSyncable(_scriptEngine.get());
LINFO("Finished initializing");
return true;
}
@@ -865,6 +963,11 @@ void OpenSpaceEngine::setRunTime(double d){
void OpenSpaceEngine::preSynchronization() {
FileSys.triggerFilesystemEvents();
if (_switchScene) {
loadScene(_scenePath);
_switchScene = false;
}
if (_isFirstRenderingFirstFrame) {
_windowWrapper->setSynchronization(false);
}
@@ -883,7 +986,7 @@ void OpenSpaceEngine::preSynchronization() {
_interactionHandler->updateInputStates(dt);
_renderEngine->updateSceneGraph();
_renderEngine->updateScene();
_interactionHandler->updateCamera(dt);
_renderEngine->camera()->invalidateCache();
@@ -902,7 +1005,7 @@ void OpenSpaceEngine::postSynchronizationPreDraw() {
_shutdownCountdown -= _windowWrapper->averageDeltaTime();
}
_renderEngine->updateSceneGraph();
_renderEngine->updateScene();
_renderEngine->updateFade();
_renderEngine->updateRenderer();
_renderEngine->updateScreenSpaceRenderables();

View File

@@ -141,19 +141,23 @@ void SettingsEngine::initSceneFiles() {
// Load all matching files in the Scene
// TODO: match regex with either with new ghoul readFiles or local code
std::string sceneDir = "${SCENE}";
std::string pathSep(1, ghoul::filesystem::FileSystem::PathSeparator);
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("/\\");
std::size_t found = scenes[i].find_last_of(pathSep);
_scenes.addOption(i, scenes[i].substr(found+1));
}
// Set interaction to change ConfigurationManager and schedule the load
_scenes.onChange(
[this]() {
[this, sceneDir, pathSep]() {
std::string sceneFile = _scenes.getDescriptionByValue(_scenes);
OsEng.configurationManager().setValue(
ConfigurationManager::KeyConfigScene, sceneFile);
OsEng.renderEngine().scene()->scheduleLoadSceneFile(sceneFile);
std::string fullPath =
sceneDir + pathSep + sceneFile;
OsEng.scheduleLoadScene(fullPath);
}
);
}

View File

@@ -44,7 +44,6 @@ namespace openspace {
}
void SyncEngine::presync(bool isMaster) {
for (const auto& syncable : _syncables) {
syncable->presync(isMaster);
@@ -73,8 +72,6 @@ namespace openspace {
}
}
void SyncEngine::addSyncable(Syncable* syncable) {
_syncables.push_back(syncable);
}
@@ -92,4 +89,10 @@ namespace openspace {
);
}
void SyncEngine::removeSyncables(const std::vector<Syncable*>& syncables) {
for (const auto& syncable : syncables) {
removeSyncable(syncable);
}
}
}

View File

@@ -72,7 +72,6 @@ namespace interaction {
// InteractionHandler
InteractionHandler::InteractionHandler()
: _origin("origin", "Origin", "")
, _coordinateSystem("coordinateSystem", "Coordinate System", "")
, _rotationalFriction("rotationalFriction", "Rotational Friction", true)
, _horizontalFriction("horizontalFriction", "Horizontal Friction", true)
, _verticalFriction("verticalFriction", "Vertical Friction", true)
@@ -91,10 +90,6 @@ InteractionHandler::InteractionHandler()
resetCameraDirection();
});
_coordinateSystem.onChange([this]() {
OsEng.renderEngine().changeViewPoint(_coordinateSystem.value());
});
// Create the interactionModes
_inputState = std::make_unique<InputState>();
// Inject the same mouse states to both orbital and global interaction mode
@@ -137,7 +132,6 @@ InteractionHandler::InteractionHandler()
// Add the properties
addProperty(_origin);
addProperty(_coordinateSystem);
addProperty(_rotationalFriction);
addProperty(_horizontalFriction);
@@ -175,6 +169,7 @@ void InteractionHandler::setFocusNode(SceneGraphNode* node) {
void InteractionHandler::setCamera(Camera* camera) {
_camera = camera;
setFocusNode(_camera->parent());
}
void InteractionHandler::resetCameraDirection() {

View File

@@ -44,7 +44,6 @@
#include <openspace/documentation/documentationengine.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/interaction/interactionhandler.h>
#include <openspace/scene/scene.h>
#include <openspace/util/camera.h>
#include <openspace/util/time.h>
@@ -113,14 +112,14 @@ const std::vector<RenderEngine::FrametimeType> RenderEngine::FrametimeTypes({
});
RenderEngine::RenderEngine()
: _mainCamera(nullptr)
: _camera(nullptr)
, _performanceMeasurements("performanceMeasurements", "Performance Measurements")
, _frametimeType(
"frametimeType",
"Type of the frametime display",
properties::OptionProperty::DisplayType::Dropdown
)
, _sceneGraph(nullptr)
, _scene(nullptr)
, _renderer(nullptr)
, _rendererImplementation(RendererImplementation::Invalid)
, _performanceManager(nullptr)
@@ -166,23 +165,11 @@ RenderEngine::RenderEngine()
addProperty(_frametimeType);
}
RenderEngine::~RenderEngine() {
delete _sceneGraph;
_sceneGraph = nullptr;
delete _mainCamera;
delete _raycasterManager;
}
bool RenderEngine::deinitialize() {
for (auto screenspacerenderable : _screenSpaceRenderables) {
screenspacerenderable->deinitialize();
}
MissionManager::deinitialize();
_sceneGraph->clearSceneGraph();
return true;
}
@@ -209,8 +196,7 @@ bool RenderEngine::initialize() {
_frameNumber = 0;
std::string renderingMethod = DefaultRenderingMethod;
// If the user specified a rendering method that he would like to use, use that
// Set rendering method to the user-defined one if any.
if (OsEng.configurationManager().hasKeyAndValue<std::string>(KeyRenderingMethod)) {
renderingMethod = OsEng.configurationManager().value<std::string>(KeyRenderingMethod);
} else {
@@ -224,20 +210,12 @@ bool 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
@@ -279,79 +257,6 @@ bool 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();
@@ -361,8 +266,8 @@ bool RenderEngine::initializeGL() {
return true;
}
void RenderEngine::updateSceneGraph() {
_sceneGraph->update({
void RenderEngine::updateScene() {
_scene->update({
glm::dvec3(0),
glm::dmat3(1),
1,
@@ -373,13 +278,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);
}
void RenderEngine::updateShaderPrograms() {
@@ -466,8 +365,8 @@ void RenderEngine::updateFade() {
}
void RenderEngine::render(const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix){
_mainCamera->sgctInternal.setViewMatrix(viewMatrix);
_mainCamera->sgctInternal.setProjectionMatrix(projectionMatrix);
_camera->sgctInternal.setViewMatrix(viewMatrix);
_camera->sgctInternal.setProjectionMatrix(projectionMatrix);
if (!(OsEng.isMaster() && _disableMasterRendering) && !OsEng.windowWrapper().isGuiWindow()) {
_renderer->render(_globalBlackOutFactor, _performanceManager != nullptr);
@@ -546,20 +445,29 @@ void RenderEngine::toggleInfoText(bool b) {
}
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 {
@@ -718,8 +626,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);
}
@@ -803,395 +711,6 @@ performance::PerformanceManager* RenderEngine::performanceManager() {
return _performanceManager.get();
}
// This method is temporary and will be removed once the scalegraph is in effect ---abock
void RenderEngine::changeViewPoint(std::string origin) {
// SceneGraphNode* solarSystemBarycenterNode = scene()->sceneGraphNode("SolarSystemBarycenter");
// SceneGraphNode* plutoBarycenterNode = scene()->sceneGraphNode("PlutoBarycenter");
// SceneGraphNode* newHorizonsNode = scene()->sceneGraphNode("NewHorizons");
// SceneGraphNode* newHorizonsPathNodeJ = scene()->sceneGraphNode("NewHorizonsPathJupiter");
// SceneGraphNode* newHorizonsPathNodeP = scene()->sceneGraphNode("NewHorizonsPathPluto");
//// SceneGraphNode* cg67pNode = scene()->sceneGraphNode("67P");
//// SceneGraphNode* rosettaNode = scene()->sceneGraphNode("Rosetta");
//
// RenderablePath* nhPath;
//
// SceneGraphNode* jupiterBarycenterNode = scene()->sceneGraphNode("JupiterBarycenter");
//
// //SceneGraphNode* newHorizonsGhostNode = scene()->sceneGraphNode("NewHorizonsGhost");
// //SceneGraphNode* dawnNode = scene()->sceneGraphNode("Dawn");
// //SceneGraphNode* vestaNode = scene()->sceneGraphNode("Vesta");
//
// // if (solarSystemBarycenterNode == nullptr || plutoBarycenterNode == nullptr ||
// //jupiterBarycenterNode == nullptr) {
// // LERROR("Necessary nodes does not exist");
// //return;
// // }
//
// if (origin == "Pluto") {
// if (newHorizonsPathNodeP) {
// Renderable* R = newHorizonsPathNodeP->renderable();
// newHorizonsPathNodeP->setParent(plutoBarycenterNode);
// nhPath = static_cast<RenderablePath*>(R);
// nhPath->calculatePath("PLUTO BARYCENTER");
// }
//
// plutoBarycenterNode->setParent(scene()->sceneGraphNode("SolarSystem"));
// plutoBarycenterNode->setEphemeris(new StaticEphemeris);
//
// solarSystemBarycenterNode->setParent(plutoBarycenterNode);
// newHorizonsNode->setParent(plutoBarycenterNode);
// //newHorizonsGhostNode->setParent(plutoBarycenterNode);
//
// //dawnNode->setParent(plutoBarycenterNode);
// //vestaNode->setParent(plutoBarycenterNode);
//
// //newHorizonsTrailNode->setParent(plutoBarycenterNode);
// ghoul::Dictionary solarDictionary =
// {
// { std::string("Type"), std::string("Spice") },
// { std::string("Body"), std::string("SUN") },
// { std::string("Reference"), std::string("GALACTIC") },
// { std::string("Observer"), std::string("PLUTO BARYCENTER") },
// { std::string("Kernels"), ghoul::Dictionary() }
// };
//
// ghoul::Dictionary jupiterDictionary =
// {
// { std::string("Type"), std::string("Spice") },
// { std::string("Body"), std::string("JUPITER BARYCENTER") },
// { std::string("Reference"), std::string("GALACTIC") },
// { std::string("Observer"), std::string("PLUTO BARYCENTER") },
// { std::string("Kernels"), ghoul::Dictionary() }
// };
//
// ghoul::Dictionary newHorizonsDictionary =
// {
// { std::string("Type"), std::string("Spice") },
// { std::string("Body"), std::string("NEW HORIZONS") },
// { std::string("Reference"), std::string("GALACTIC") },
// { std::string("Observer"), std::string("PLUTO BARYCENTER") },
// { std::string("Kernels"), ghoul::Dictionary() }
// };
//
// solarSystemBarycenterNode->setEphemeris(new SpiceEphemeris(solarDictionary));
// jupiterBarycenterNode->setEphemeris(new SpiceEphemeris(jupiterDictionary));
// newHorizonsNode->setEphemeris(new SpiceEphemeris(newHorizonsDictionary));
// //newHorizonsTrailNode->setEphemeris(new SpiceEphemeris(newHorizonsDictionary));
//
//
// //ghoul::Dictionary dawnDictionary =
// //{
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("DAWN") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("PLUTO BARYCENTER") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// //};
// //dawnNode->setEphemeris(new SpiceEphemeris(dawnDictionary));
// //
// //ghoul::Dictionary vestaDictionary =
// //{
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("VESTA") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("PLUTO BARYCENTER") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// //};
// //vestaNode->setEphemeris(new SpiceEphemeris(vestaDictionary));
//
//
// //ghoul::Dictionary newHorizonsGhostDictionary =
// //{
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("NEW HORIZONS") },
// // { std::string("EphmerisGhosting"), std::string("TRUE") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("PLUTO BARYCENTER") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// //};
// //newHorizonsGhostNode->setEphemeris(new SpiceEphemeris(newHorizonsGhostDictionary));
//
// return;
// }
// if (origin == "Sun") {
// solarSystemBarycenterNode->setParent(scene()->sceneGraphNode("SolarSystem"));
//
// if (plutoBarycenterNode)
// plutoBarycenterNode->setParent(solarSystemBarycenterNode);
// jupiterBarycenterNode->setParent(solarSystemBarycenterNode);
// if (newHorizonsNode)
// newHorizonsNode->setParent(solarSystemBarycenterNode);
// //newHorizonsGhostNode->setParent(solarSystemBarycenterNode);
//
// //newHorizonsTrailNode->setParent(solarSystemBarycenterNode);
// //dawnNode->setParent(solarSystemBarycenterNode);
// //vestaNode->setParent(solarSystemBarycenterNode);
//
// ghoul::Dictionary plutoDictionary =
// {
// { std::string("Type"), std::string("Spice") },
// { std::string("Body"), std::string("PLUTO BARYCENTER") },
// { std::string("Reference"), std::string("GALACTIC") },
// { std::string("Observer"), std::string("SUN") },
// { std::string("Kernels"), ghoul::Dictionary() }
// };
// ghoul::Dictionary jupiterDictionary =
// {
// { std::string("Type"), std::string("Spice") },
// { std::string("Body"), std::string("JUPITER BARYCENTER") },
// { std::string("Reference"), std::string("GALACTIC") },
// { std::string("Observer"), std::string("SUN") },
// { std::string("Kernels"), ghoul::Dictionary() }
// };
//
// solarSystemBarycenterNode->setEphemeris(new StaticEphemeris);
// jupiterBarycenterNode->setEphemeris(new SpiceEphemeris(jupiterDictionary));
// if (plutoBarycenterNode)
// plutoBarycenterNode->setEphemeris(new SpiceEphemeris(plutoDictionary));
//
// ghoul::Dictionary newHorizonsDictionary =
// {
// { std::string("Type"), std::string("Spice") },
// { std::string("Body"), std::string("NEW HORIZONS") },
// { std::string("Reference"), std::string("GALACTIC") },
// { std::string("Observer"), std::string("SUN") },
// { std::string("Kernels"), ghoul::Dictionary() }
// };
// if (newHorizonsNode)
// newHorizonsNode->setEphemeris(new SpiceEphemeris(newHorizonsDictionary));
// //newHorizonsTrailNode->setEphemeris(new SpiceEphemeris(newHorizonsDictionary));
//
//
// //ghoul::Dictionary dawnDictionary =
// //{
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("DAWN") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("SUN") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// //};
// //dawnNode->setEphemeris(new SpiceEphemeris(dawnDictionary));
// //
// //ghoul::Dictionary vestaDictionary =
// //{
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("VESTA") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("SUN") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// //};
// //vestaNode->setEphemeris(new SpiceEphemeris(vestaDictionary));
//
//
// //ghoul::Dictionary newHorizonsGhostDictionary =
// //{
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("NEW HORIZONS") },
// // { std::string("EphmerisGhosting"), std::string("TRUE") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("JUPITER BARYCENTER") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// //};
// //newHorizonsGhostNode->setEphemeris(new SpiceEphemeris(newHorizonsGhostDictionary));
//
// return;
// }
// if (origin == "Jupiter") {
// if (newHorizonsPathNodeJ) {
// Renderable* R = newHorizonsPathNodeJ->renderable();
// newHorizonsPathNodeJ->setParent(jupiterBarycenterNode);
// nhPath = static_cast<RenderablePath*>(R);
// nhPath->calculatePath("JUPITER BARYCENTER");
// }
//
// jupiterBarycenterNode->setParent(scene()->sceneGraphNode("SolarSystem"));
// jupiterBarycenterNode->setEphemeris(new StaticEphemeris);
//
// solarSystemBarycenterNode->setParent(jupiterBarycenterNode);
// if (newHorizonsNode)
// newHorizonsNode->setParent(jupiterBarycenterNode);
// //newHorizonsTrailNode->setParent(jupiterBarycenterNode);
//
// //dawnNode->setParent(jupiterBarycenterNode);
// //vestaNode->setParent(jupiterBarycenterNode);
//
//
// ghoul::Dictionary solarDictionary =
// {
// { std::string("Type"), std::string("Spice") },
// { std::string("Body"), std::string("SUN") },
// { std::string("Reference"), std::string("GALACTIC") },
// { std::string("Observer"), std::string("JUPITER BARYCENTER") },
// { std::string("Kernels"), ghoul::Dictionary() }
// };
//
// ghoul::Dictionary plutoDictionary =
// {
// { std::string("Type"), std::string("Spice") },
// { std::string("Body"), std::string("PlUTO BARYCENTER") },
// { std::string("Reference"), std::string("GALACTIC") },
// { std::string("Observer"), std::string("JUPITER BARYCENTER") },
// { std::string("Kernels"), ghoul::Dictionary() }
// };
//
// ghoul::Dictionary newHorizonsDictionary =
// {
// { std::string("Type"), std::string("Spice") },
// { std::string("Body"), std::string("NEW HORIZONS") },
// { std::string("Reference"), std::string("GALACTIC") },
// { std::string("Observer"), std::string("JUPITER BARYCENTER") },
// { std::string("Kernels"), ghoul::Dictionary() }
// };
// solarSystemBarycenterNode->setEphemeris(new SpiceEphemeris(solarDictionary));
// if (plutoBarycenterNode)
// plutoBarycenterNode->setEphemeris(new SpiceEphemeris(plutoDictionary));
// if (newHorizonsNode)
// newHorizonsNode->setEphemeris(new SpiceEphemeris(newHorizonsDictionary));
// //newHorizonsGhostNode->setParent(jupiterBarycenterNode);
// //newHorizonsTrailNode->setEphemeris(new SpiceEphemeris(newHorizonsDictionary));
//
//
// //ghoul::Dictionary dawnDictionary =
// //{
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("DAWN") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("JUPITER BARYCENTER") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// //};
// //dawnNode->setEphemeris(new SpiceEphemeris(dawnDictionary));
// //
// //ghoul::Dictionary vestaDictionary =
// //{
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("VESTA") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("JUPITER BARYCENTER") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// //};
// //vestaNode->setEphemeris(new SpiceEphemeris(vestaDictionary));
//
//
//
// //ghoul::Dictionary newHorizonsGhostDictionary =
// //{
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("NEW HORIZONS") },
// // { std::string("EphmerisGhosting"), std::string("TRUE") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("JUPITER BARYCENTER") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// //};
// //newHorizonsGhostNode->setEphemeris(new SpiceEphemeris(newHorizonsGhostDictionary));
// //newHorizonsGhostNode->setParent(jupiterBarycenterNode);
//
//
// return;
// }
// //if (origin == "Vesta") {
// //
// // vestaNode->setParent(scene()->sceneGraphNode("SolarSystem"));
// // vestaNode->setEphemeris(new StaticEphemeris);
// //
// // solarSystemBarycenterNode->setParent(vestaNode);
// // newHorizonsNode->setParent(vestaNode);
// //
// // dawnNode->setParent(vestaNode);
// // plutoBarycenterNode->setParent(vestaNode);
// //
// //
// // ghoul::Dictionary plutoDictionary =
// // {
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("PLUTO BARYCENTER") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("VESTA") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// // };
// // ghoul::Dictionary solarDictionary =
// // {
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("SUN") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("VESTA") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// // };
// //
// // ghoul::Dictionary jupiterDictionary =
// // {
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("JUPITER BARYCENTER") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("VESTA") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// // };
// //
// // solarSystemBarycenterNode->setEphemeris(new SpiceEphemeris(solarDictionary));
// // plutoBarycenterNode->setEphemeris(new SpiceEphemeris(plutoDictionary));
// // jupiterBarycenterNode->setEphemeris(new SpiceEphemeris(jupiterDictionary));
// //
// // ghoul::Dictionary newHorizonsDictionary =
// // {
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("NEW HORIZONS") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("VESTA") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// // };
// // newHorizonsNode->setEphemeris(new SpiceEphemeris(newHorizonsDictionary));
// //
// // ghoul::Dictionary dawnDictionary =
// // {
// // { std::string("Type"), std::string("Spice") },
// // { std::string("Body"), std::string("DAWN") },
// // { std::string("Reference"), std::string("GALACTIC") },
// // { std::string("Observer"), std::string("VESTA") },
// // { std::string("Kernels"), ghoul::Dictionary() }
// // };
// // dawnNode->setEphemeris(new SpiceEphemeris(dawnDictionary));
// // vestaNode->setEphemeris(new StaticEphemeris);
// //
// // return;
// //}
//
// if (origin == "67P") {
// SceneGraphNode* rosettaNode = scene()->sceneGraphNode("Rosetta");
// SceneGraphNode* cgNode = scene()->sceneGraphNode("67P");
// //jupiterBarycenterNode->setParent(solarSystemBarycenterNode);
// //plutoBarycenterNode->setParent(solarSystemBarycenterNode);
// solarSystemBarycenterNode->setParent(cgNode);
// rosettaNode->setParent(cgNode);
//
// ghoul::Dictionary solarDictionary =
// {
// { std::string("Type"), std::string("Spice") },
// { std::string("Body"), std::string("SUN") },
// { std::string("Reference"), std::string("GALACTIC") },
// { std::string("Observer"), std::string("CHURYUMOV-GERASIMENKO") },
// { std::string("Kernels"), ghoul::Dictionary() }
// };
// solarSystemBarycenterNode->setEphemeris(new SpiceEphemeris(solarDictionary));
//
// ghoul::Dictionary rosettaDictionary =
// {
// { std::string("Type"), std::string("Spice") },
// { std::string("Body"), std::string("ROSETTA") },
// { std::string("Reference"), std::string("GALACTIC") },
// { std::string("Observer"), std::string("CHURYUMOV-GERASIMENKO") },
// { std::string("Kernels"), ghoul::Dictionary() }
// };
//
// cgNode->setParent(scene()->sceneGraphNode("SolarSystem"));
// rosettaNode->setEphemeris(new SpiceEphemeris(rosettaDictionary));
// cgNode->setEphemeris(new StaticEphemeris);
//
// return;
//
// }
//
// LFATAL("This function is being misused with an argument of '" << origin << "'");
}
void RenderEngine::setShowFrameNumber(bool enabled){
_showFrameNumber = enabled;
}
@@ -1370,21 +889,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) {
@@ -1734,7 +1244,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>
@@ -53,6 +54,8 @@
#include <numeric>
#include <fstream>
#include <string>
#include <stack>
#include <unordered_map>
#ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED
#include <modules/onscreengui/include/gui.h>
@@ -82,142 +85,121 @@ 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, Scene::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, Scene::UpdateDependencies updateDeps) {
// Remove the node and all its children.
node->traversePostOrder([this](SceneGraphNode* n) {
_topologicallySortedNodes.erase(std::remove(_topologicallySortedNodes.begin(), _topologicallySortedNodes.end(), n), _topologicallySortedNodes.end());
_nodesByName.erase(n->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() {
std::copy(_circularNodes.begin(), _circularNodes.end(), std::back_inserter(_topologicallySortedNodes));
_circularNodes.clear();
ghoul_assert(_topologicallySortedNodes.size() == _nodesByName.size(), "Number of scene graph nodes is inconsistent");
if (_topologicallySortedNodes.empty())
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::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);
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;
}
}
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 (auto& n : node->dependentNodes()) {
auto it = inDegrees.find(n);
it->second -= 1;
if (it->second == 0) {
zeroInDegreeNodes.push(n);
inDegrees.erase(it);
}
LINFO("Loaded " << _sceneGraphToLoad);
_sceneGraphToLoad = "";
}
catch (const ghoul::RuntimeError& e) {
LERROR(e.what());
_sceneGraphToLoad = "";
return;
for (auto& n : node->children()) {
auto it = inDegrees.find(n);
it->second -= 1;
if (it->second == 0) {
zeroInDegreeNodes.push(n);
inDegrees.erase(it);
}
}
}
for (SceneGraphNode* node : _graph.nodes()) {
try {
node->update(data);
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.what());
}
if (inDegrees.size() > 0) {
LERROR("The scene contains circular dependencies. " << inDegrees.size() << " nodes will be disabled.");
}
}
void Scene::evaluate(Camera* camera) {
for (SceneGraphNode* node : _graph.nodes())
node->evaluate(camera);
//_root->evaluate(camera);
}
void Scene::render(const RenderData& data, RendererTasks& tasks) {
for (SceneGraphNode* node : _graph.nodes()) {
node->render(data, tasks);
for (auto& it : inDegrees) {
_circularNodes.push_back(it.first);
}
_topologicallySortedNodes = nodes;
}
void Scene::scheduleLoadSceneFile(const std::string& sceneDescriptionFilePath) {
_sceneGraphToLoad = sceneDescriptionFilePath;
}
void Scene::clearSceneGraph() {
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();
}
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()) {
void Scene::initialize() {
for (SceneGraphNode* node : _topologicallySortedNodes) {
try {
bool success = node->initialize();
if (success)
@@ -229,221 +211,64 @@ bool Scene::loadSceneInternal(const std::string& sceneDescriptionFilePath) {
LERRORC(_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;
}
//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::update(const UpdateData& data) {
for (auto& node : _topologicallySortedNodes) {
try {
node->update(data);
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.what());
}
}
}
//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::evaluate(Camera* camera) {
for (auto& node : _topologicallySortedNodes) {
try {
node->evaluate(camera);
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.what());
}
}
}
//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 Scene::render(const RenderData& data, RendererTasks& tasks) {
for (auto& node : _topologicallySortedNodes) {
try {
node->render(data, tasks);
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.what());
}
}
}
//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);
//}
void Scene::clear() {
LINFO("Clearing current scene graph");
_root = nullptr;
}
const std::map<std::string, SceneGraphNode*>& Scene::nodesByName() const {
return _nodesByName;
}
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) {
@@ -454,7 +279,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;
@@ -544,7 +369,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()),
@@ -595,45 +420,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
@@ -700,4 +486,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,578 +0,0 @@
/*****************************************************************************************
* *
* 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/scene/scenegraph.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 (...) {
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

@@ -66,14 +66,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);
@@ -88,7 +88,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);
@@ -103,7 +102,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());
@@ -118,7 +116,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());
@@ -133,7 +130,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());
@@ -142,11 +138,12 @@ SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& di
LDEBUG("Successfully created SceneGraphNode '"
<< result->name() << "'");
return result;
return std::move(result);
}
SceneGraphNode::SceneGraphNode()
: _parent(nullptr)
, _scene(nullptr)
, _transform {
std::make_unique<StaticTranslation>(),
std::make_unique<StaticRotation>(),
@@ -201,6 +198,20 @@ bool SceneGraphNode::deinitialize() {
return true;
}
void SceneGraphNode::traversePreOrder(std::function<void(SceneGraphNode*)> fn) {
fn(this);
for (auto& child : _children) {
child->traversePreOrder(fn);
}
}
void SceneGraphNode::traversePostOrder(std::function<void(SceneGraphNode*)> fn) {
for (auto& child : _children) {
child->traversePostOrder(fn);
}
fn(this);
}
void SceneGraphNode::update(const UpdateData& data) {
if (_transform.translation) {
if (data.doPerformanceMeasurement) {
@@ -366,26 +377,135 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) {
// _children.push_back(child);
//}
void SceneGraphNode::setParent(SceneGraphNode* parent) {
_parent = parent;
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"
);
parent.attachChild(_parent->detachChild(*this, UpdateScene::No), UpdateScene::No);
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);
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();
}
}
//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;
//}
const std::vector<SceneGraphNode*>& SceneGraphNode::dependencies() const {
return _dependencies;
}
const std::vector<SceneGraphNode*>& SceneGraphNode::dependentNodes() const {
return _dependentNodes;
}
glm::dvec3 SceneGraphNode::position() const
{
@@ -451,15 +571,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;
@@ -490,7 +623,6 @@ PowerScaledScalar SceneGraphNode::calculateBoundingSphere(){
if(renderableBS > _boundingSphere)
_boundingSphere = renderableBS;
}
//LINFO("Bounding Sphere of '" << name() << "': " << _boundingSphere);
return _boundingSphere;
}
@@ -499,13 +631,11 @@ PowerScaledScalar SceneGraphNode::boundingSphere() const{
return _boundingSphere;
}
// renderable
void SceneGraphNode::setRenderable(Renderable* renderable) {
_renderable = renderable;
}
const Renderable* SceneGraphNode::renderable() const
{
const Renderable* SceneGraphNode::renderable() const {
return _renderable;
}
@@ -513,7 +643,7 @@ Renderable* SceneGraphNode::renderable() {
return _renderable;
}
// private helper methods
/*
bool SceneGraphNode::sphereInsideFrustum(const psc& s_pos, const PowerScaledScalar& s_rad,
const Camera* camera)
{
@@ -544,15 +674,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 (auto& it : _children) {
SceneGraphNode* tmp = it->childNode(name);
if (tmp != nullptr)
if (tmp)
return tmp;
}
return nullptr;

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

@@ -0,0 +1,391 @@
/*****************************************************************************************
* *
* 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>
#include <memory>
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);
}
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);
}
}
// Add the nodes to the scene.
for (auto& node : attachedBranches) {
scene.addNode(node, Scene::UpdateDependencies::No);
}
// 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");
}
}
// Update dependencies: sort nodes topologically.
scene.updateDependencies();
// Return a vector of all added nodes.
std::vector<SceneGraphNode*> addedNodesVector;
for (auto& it : addedNodes) {
addedNodesVector.push_back(it.second);
}
return addedNodesVector;
}
}

View File

@@ -0,0 +1,48 @@
/*****************************************************************************************
* *
* 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/scene/scenemanager.h>
#include <openspace/scene/sceneloader.h>
#include <algorithm>
#include <memory>
#include <openspace/scene/scene.h>
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;
});
}
}

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

@@ -33,7 +33,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-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 "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-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 "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.
}