From b444bfd77a22f0f046c8767b9492f11a4b279d1a Mon Sep 17 00:00:00 2001
From: Alexander Bock
Date: Sun, 23 Oct 2016 21:49:04 +0200
Subject: [PATCH 01/43] Making iSWA compile with the changes in the
ScriptManager
---
modules/iswa/rendering/iswacygnet.cpp | 10 ++++-
modules/iswa/rendering/iswakameleongroup.cpp | 10 ++++-
modules/iswa/rendering/kameleonplane.cpp | 5 ++-
modules/iswa/rendering/screenspacecygnet.cpp | 3 +-
modules/iswa/util/iswamanager.cpp | 33 ++++++++------
modules/iswa/util/iswamanager_lua.inl | 10 ++++-
modules/onscreengui/src/guiiswacomponent.cpp | 46 +++++++++++++++-----
7 files changed, 84 insertions(+), 33 deletions(-)
diff --git a/modules/iswa/rendering/iswacygnet.cpp b/modules/iswa/rendering/iswacygnet.cpp
index 53610bf633..005062a21a 100644
--- a/modules/iswa/rendering/iswacygnet.cpp
+++ b/modules/iswa/rendering/iswacygnet.cpp
@@ -107,7 +107,10 @@ bool IswaCygnet::initialize(){
}else{
_delete.onChange([this](){
deinitialize();
- OsEng.scriptEngine().queueScript("openspace.removeSceneGraphNode('" + name() + "')");
+ OsEng.scriptEngine().queueScript(
+ "openspace.removeSceneGraphNode('" + name() + "')",
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
});
}
@@ -260,7 +263,10 @@ void IswaCygnet::initializeGroup(){
groupEvent->subscribe(name(), "clearGroup", [&](ghoul::Dictionary dict){
LDEBUG(name() + " Event clearGroup");
- OsEng.scriptEngine().queueScript("openspace.removeSceneGraphNode('" + name() + "')");
+ OsEng.scriptEngine().queueScript(
+ "openspace.removeSceneGraphNode('" + name() + "')",
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
});
}
diff --git a/modules/iswa/rendering/iswakameleongroup.cpp b/modules/iswa/rendering/iswakameleongroup.cpp
index 4273f8330e..c48b5a36b7 100644
--- a/modules/iswa/rendering/iswakameleongroup.cpp
+++ b/modules/iswa/rendering/iswakameleongroup.cpp
@@ -130,7 +130,10 @@ void IswaKameleonGroup::updateFieldlineSeeds(){
// if this option was turned off
if( std::find(selectedOptions.begin(), selectedOptions.end(), seedPath.first)==selectedOptions.end() && std::get<2>(seedPath.second)){
LDEBUG("Removed fieldlines: " + std::get<0>(seedPath.second));
- OsEng.scriptEngine().queueScript("openspace.removeSceneGraphNode('" + std::get<0>(seedPath.second) + "')");
+ OsEng.scriptEngine().queueScript(
+ "openspace.removeSceneGraphNode('" + std::get<0>(seedPath.second) + "')",
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
std::get<2>(seedPath.second) = false;
// if this option was turned on
} else if( std::find(selectedOptions.begin(), selectedOptions.end(), seedPath.first)!=selectedOptions.end() && !std::get<2>(seedPath.second)) {
@@ -146,7 +149,10 @@ void IswaKameleonGroup::clearFieldlines(){
for (auto& seedPath: _fieldlineState) {
if(std::get<2>(seedPath.second)){
LDEBUG("Removed fieldlines: " + std::get<0>(seedPath.second));
- OsEng.scriptEngine().queueScript("openspace.removeSceneGraphNode('" + std::get<0>(seedPath.second) + "')");
+ OsEng.scriptEngine().queueScript(
+ "openspace.removeSceneGraphNode('" + std::get<0>(seedPath.second) + "')",
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
std::get<2>(seedPath.second) = false;
}
}
diff --git a/modules/iswa/rendering/kameleonplane.cpp b/modules/iswa/rendering/kameleonplane.cpp
index 9a5dab1125..b316147738 100644
--- a/modules/iswa/rendering/kameleonplane.cpp
+++ b/modules/iswa/rendering/kameleonplane.cpp
@@ -232,7 +232,10 @@ void KameleonPlane::updateFieldlineSeeds(){
if(OsEng.renderEngine().scene()->sceneGraphNode(std::get<0>(seedPath.second)) == nullptr) return;
LDEBUG("Removed fieldlines: " + std::get<0>(seedPath.second));
- OsEng.scriptEngine().queueScript("openspace.removeSceneGraphNode('" + std::get<0>(seedPath.second) + "')");
+ OsEng.scriptEngine().queueScript(
+ "openspace.removeSceneGraphNode('" + std::get<0>(seedPath.second) + "')",
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
std::get<2>(seedPath.second) = false;
// if this option was turned on
} else if( std::find(selectedOptions.begin(), selectedOptions.end(), seedPath.first)!=selectedOptions.end() && !std::get<2>(seedPath.second)) {
diff --git a/modules/iswa/rendering/screenspacecygnet.cpp b/modules/iswa/rendering/screenspacecygnet.cpp
index 73eb771e28..32c2c340a0 100644
--- a/modules/iswa/rendering/screenspacecygnet.cpp
+++ b/modules/iswa/rendering/screenspacecygnet.cpp
@@ -59,7 +59,8 @@ ScreenSpaceCygnet::ScreenSpaceCygnet(const ghoul::Dictionary& dictionary)
_delete.onChange([this](){
OsEng.scriptEngine().queueScript(
- "openspace.iswa.removeScreenSpaceCygnet("+std::to_string(_cygnetId)+");"
+ "openspace.iswa.removeScreenSpaceCygnet("+std::to_string(_cygnetId)+");",
+ scripting::ScriptEngine::RemoteScripting::Yes
);
});
// IswaManager::ref().deleteIswaCygnet(name());});
diff --git a/modules/iswa/util/iswamanager.cpp b/modules/iswa/util/iswamanager.cpp
index bad0b41bf7..63976748ca 100644
--- a/modules/iswa/util/iswamanager.cpp
+++ b/modules/iswa/util/iswamanager.cpp
@@ -439,7 +439,10 @@ std::string IswaManager::jsonSphereToLuaTable(std::shared_ptr da
void IswaManager::createScreenSpace(int id){
std::string script = "openspace.iswa.addScreenSpaceCygnet("
"{CygnetId =" + std::to_string(id) + "});";
- OsEng.scriptEngine().queueScript(script);
+ OsEng.scriptEngine().queueScript(
+ script,
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
}
void IswaManager::createPlane(std::shared_ptr data){
@@ -475,7 +478,10 @@ void IswaManager::createPlane(std::shared_ptr data){
std::string luaTable = jsonPlaneToLuaTable(data);
if(luaTable != ""){
std::string script = "openspace.addSceneGraphNode(" + luaTable + ");";
- OsEng.scriptEngine().queueScript(script);
+ OsEng.scriptEngine().queueScript(
+ script,
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
}
}
@@ -504,7 +510,10 @@ void IswaManager::createSphere(std::shared_ptr data){
std::string luaTable = jsonSphereToLuaTable(data);
if(luaTable != ""){
std::string script = "openspace.addSceneGraphNode(" + luaTable + ");";
- OsEng.scriptEngine().queueScript(script);
+ OsEng.scriptEngine().queueScript(
+ script,
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
}
}
@@ -536,7 +545,10 @@ void IswaManager::createKameleonPlane(CdfInfo info, std::string cut){
std::string luaTable = parseKWToLuaTable(info, cut);
if(!luaTable.empty()){
std::string script = "openspace.addSceneGraphNode(" + luaTable + ");";
- OsEng.scriptEngine().queueScript(script);
+ OsEng.scriptEngine().queueScript(
+ script,
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
}
}else{
LWARNING( absPath(info.path) + " is not a cdf file or can't be found.");
@@ -570,7 +582,10 @@ void IswaManager::createFieldline(std::string name, std::string cdfPath, std::st
"}";
if(!luaTable.empty()){
std::string script = "openspace.addSceneGraphNode(" + luaTable + ");";
- OsEng.scriptEngine().queueScript(script);
+ OsEng.scriptEngine().queueScript(
+ script,
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
}
}else{
LWARNING( cdfPath + " is not a cdf file or can't be found.");
@@ -661,21 +676,18 @@ scripting::LuaLibrary IswaManager::luaLibrary() {
&luascriptfunctions::iswa_addCygnet,
"int, string, string",
"Adds a IswaCygnet",
- true
},
{
"addScreenSpaceCygnet",
&luascriptfunctions::iswa_addScreenSpaceCygnet,
"int, string, string",
"Adds a Screen Space Cygnets",
- true
},
{
"addKameleonPlanes",
&luascriptfunctions::iswa_addKameleonPlanes,
"string, int",
"Adds KameleonPlanes from cdf file.",
- true
},
// {
// "addKameleonPlane",
@@ -689,35 +701,30 @@ scripting::LuaLibrary IswaManager::luaLibrary() {
&luascriptfunctions::iswa_addCdfFiles,
"string",
"Adds a cdf files to choose from.",
- true
},
{
"removeCygnet",
&luascriptfunctions::iswa_removeCygnet,
"string",
"Remove a Cygnets",
- true
},
{
"removeScreenSpaceCygnet",
&luascriptfunctions::iswa_removeScrenSpaceCygnet,
"int",
"Remove a Screen Space Cygnets",
- true
},
{
"removeGroup",
&luascriptfunctions::iswa_removeGroup,
"int",
"Remove a group of Cygnets",
- true
},
{
"setBaseUrl",
&luascriptfunctions::iswa_setBaseUrl,
"string",
"sets the base url",
- true
}
}
};
diff --git a/modules/iswa/util/iswamanager_lua.inl b/modules/iswa/util/iswamanager_lua.inl
index 703a053ba0..1a704b8aee 100644
--- a/modules/iswa/util/iswamanager_lua.inl
+++ b/modules/iswa/util/iswamanager_lua.inl
@@ -114,7 +114,10 @@ int iswa_addScreenSpaceCygnet(lua_State* L){
int iswa_removeCygnet(lua_State* L){
std::string name = luaL_checkstring(L, -1);
- OsEng.scriptEngine().queueScript("openspace.removeSceneGraphNode('" + name + "')");
+ OsEng.scriptEngine().queueScript(
+ "openspace.removeSceneGraphNode('" + name + "')",
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
// IswaManager::ref().deleteIswaCygnet(s);
return 0;
}
@@ -134,7 +137,10 @@ int iswa_removeScrenSpaceCygnet(lua_State* L){
info->selected = false;
std::string script = "openspace.unregisterScreenSpaceRenderable('" + cygnetInformation[id]->name + "');";
- OsEng.scriptEngine().queueScript(script);
+ OsEng.scriptEngine().queueScript(
+ script,
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
return 0;
}
diff --git a/modules/onscreengui/src/guiiswacomponent.cpp b/modules/onscreengui/src/guiiswacomponent.cpp
index e09a294a85..458400acae 100644
--- a/modules/onscreengui/src/guiiswacomponent.cpp
+++ b/modules/onscreengui/src/guiiswacomponent.cpp
@@ -74,7 +74,8 @@ void GuiIswaComponent::render() {
if (ImGui::SmallButton("Add Cygnet")) {
OsEng.scriptEngine().queueScript(
- "openspace.iswa.addCygnet(" + std::string(addCygnetBuffer) + ");"
+ "openspace.iswa.addCygnet(" + std::string(addCygnetBuffer) + ");",
+ scripting::ScriptEngine::RemoteScripting::Yes
);
}
@@ -83,9 +84,15 @@ void GuiIswaComponent::render() {
std::string x = "openspace.iswa.addCygnet(-4, 'Data', 'GMData');";
std::string y = "openspace.iswa.addCygnet(-5, 'Data', 'GMData');";
std::string z = "openspace.iswa.addCygnet(-6, 'Data', 'GMData');";
- OsEng.scriptEngine().queueScript(x + y + z);
+ OsEng.scriptEngine().queueScript(
+ x + y + z,
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
} else {
- OsEng.scriptEngine().queueScript("openspace.iswa.removeGroup('GMData');");
+ OsEng.scriptEngine().queueScript(
+ "openspace.iswa.removeGroup('GMData');",
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
}
}
@@ -94,19 +101,29 @@ void GuiIswaComponent::render() {
std::string x = "openspace.iswa.addCygnet(-4, 'Texture', 'GMImage');";
std::string y = "openspace.iswa.addCygnet(-5, 'Texture', 'GMImage');";
std::string z = "openspace.iswa.addCygnet(-6, 'Texture', 'GMImage');";
- OsEng.scriptEngine().queueScript(x + y + z);
+ OsEng.scriptEngine().queueScript(
+ x + y + z,
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
} else {
- OsEng.scriptEngine().queueScript("openspace.iswa.removeGroup('GMImage');");
+ OsEng.scriptEngine().queueScript(
+ "openspace.iswa.removeGroup('GMImage');",
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
}
}
if(_ionData != oldIonDataValue) {
if(_ionData) {
OsEng.scriptEngine().queueScript(
- "openspace.iswa.addCygnet(-10,'Data','Ionosphere');"
+ "openspace.iswa.addCygnet(-10,'Data','Ionosphere');",
+ scripting::ScriptEngine::RemoteScripting::Yes
);
} else {
- OsEng.scriptEngine().queueScript("openspace.iswa.removeGroup('Ionosphere');");
+ OsEng.scriptEngine().queueScript(
+ "openspace.iswa.removeGroup('Ionosphere');",
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
}
}
@@ -147,13 +164,16 @@ void GuiIswaComponent::render() {
groupName +
"'," +
std::to_string(cdfOption) +
- ");"
+ ");",
+ scripting::ScriptEngine::RemoteScripting::Yes
);
OsEng.scriptEngine().queueScript(
- "openspace.time.setTime('" + date + "');"
+ "openspace.time.setTime('" + date + "');",
+ scripting::ScriptEngine::RemoteScripting::Yes
);
OsEng.scriptEngine().queueScript(
- "openspace.time.setDeltaTime(0);"
+ "openspace.time.setDeltaTime(0);",
+ scripting::ScriptEngine::RemoteScripting::Yes
);
}
}
@@ -181,13 +201,15 @@ void GuiIswaComponent::render() {
if (info->selected) {
OsEng.scriptEngine().queueScript(
"openspace.iswa.addScreenSpaceCygnet("
- "{CygnetId = " + std::to_string(id) + " });"
+ "{CygnetId = " + std::to_string(id) + " });",
+ scripting::ScriptEngine::RemoteScripting::Yes
);
} else {
OsEng.scriptEngine().queueScript(
"openspace.iswa.removeScreenSpaceCygnet(" +
std::to_string(id) +
- ");"
+ ");",
+ scripting::ScriptEngine::RemoteScripting::Yes
);
}
}
From 317ecad9ac0b3e23cde6ae73c1c63e90c556dfe1 Mon Sep 17 00:00:00 2001
From: Alexander Bock
Date: Sun, 23 Oct 2016 22:55:26 +0200
Subject: [PATCH 02/43] Potential fix for High-DPI and manual framebuffer sizes
by using SGCT window scaling
---
include/openspace/engine/wrapper/sgctwindowwrapper.h | 1 +
include/openspace/engine/wrapper/windowwrapper.h | 7 +++++++
modules/onscreengui/include/gui.h | 2 +-
modules/onscreengui/src/gui.cpp | 4 ++--
src/engine/openspaceengine.cpp | 10 +---------
src/engine/wrapper/sgctwindowwrapper.cpp | 7 +++++++
src/engine/wrapper/windowwrapper.cpp | 4 ++++
7 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/include/openspace/engine/wrapper/sgctwindowwrapper.h b/include/openspace/engine/wrapper/sgctwindowwrapper.h
index a9c4778005..678e2fe25e 100644
--- a/include/openspace/engine/wrapper/sgctwindowwrapper.h
+++ b/include/openspace/engine/wrapper/sgctwindowwrapper.h
@@ -49,6 +49,7 @@ public:
glm::ivec2 currentWindowSize() const override;
glm::ivec2 currentWindowResolution() const override;
glm::ivec2 currentDrawBufferResolution() const override;
+ glm::vec2 dpiScaling() const override;
int currentNumberOfAaSamples() const override;
bool isRegularRendering() const override;
diff --git a/include/openspace/engine/wrapper/windowwrapper.h b/include/openspace/engine/wrapper/windowwrapper.h
index af26f105b4..75924841bc 100644
--- a/include/openspace/engine/wrapper/windowwrapper.h
+++ b/include/openspace/engine/wrapper/windowwrapper.h
@@ -138,6 +138,13 @@ public:
* \return The resolution of the currently active window in pixel coordinates
*/
virtual glm::ivec2 currentDrawBufferResolution() const;
+
+ /**
+ * Returns the DPI scaling factor for the current window. This is normally 1 on all
+ * regular monitors and 2 on Retina screens.
+ * \return The DPI scaling factor for the current window
+ */
+ virtual glm::vec2 dpiScaling() const;
/**
* Returns the number of anti-aliasing samples used in the current window.
diff --git a/modules/onscreengui/include/gui.h b/modules/onscreengui/include/gui.h
index 673e7dbb31..2c25bb36fd 100644
--- a/modules/onscreengui/include/gui.h
+++ b/modules/onscreengui/include/gui.h
@@ -56,7 +56,7 @@ public:
bool keyCallback(Key key, KeyModifier modifier, KeyAction action);
bool charCallback(unsigned int character, KeyModifier modifier);
- void startFrame(float deltaTime, const glm::vec2& windowSize, const glm::vec2& mousePosCorrectionFactor, const glm::vec2& mousePos, uint32_t mouseButtons);
+ void startFrame(float deltaTime, const glm::vec2& windowSize, const glm::vec2& dpiScaling, const glm::vec2& mousePos, uint32_t mouseButtons);
void endFrame();
void render();
diff --git a/modules/onscreengui/src/gui.cpp b/modules/onscreengui/src/gui.cpp
index e149022b67..ca2b30dbbe 100644
--- a/modules/onscreengui/src/gui.cpp
+++ b/modules/onscreengui/src/gui.cpp
@@ -406,13 +406,13 @@ void GUI::deinitializeGL() {
}
void GUI::startFrame(float deltaTime, const glm::vec2& windowSize,
- const glm::vec2& framebufferSize,
+ const glm::vec2& dpiScaling,
const glm::vec2& mousePos,
uint32_t mouseButtonsPressed)
{
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = ImVec2(windowSize.x, windowSize.y);
- io.DisplayFramebufferScale = ImVec2(framebufferSize.x / windowSize.x, framebufferSize.y / windowSize.y);
+ io.DisplayFramebufferScale = ImVec2(dpiScaling.x, dpiScaling.y);
io.DeltaTime = deltaTime;
io.MousePos = ImVec2(mousePos.x, mousePos.y);
diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp
index c9f8c35e2d..4fda144e81 100644
--- a/src/engine/openspaceengine.cpp
+++ b/src/engine/openspaceengine.cpp
@@ -898,21 +898,13 @@ void OpenSpaceEngine::postSynchronizationPreDraw() {
glm::ivec2 windowSize = _windowWrapper->currentWindowSize();
glm::ivec2 renderingSize = _windowWrapper->currentWindowResolution();
uint32_t mouseButtons = _windowWrapper->mouseButtons(2);
-
- //glm::vec2 windowBufferCorrectionFactor = glm::vec2(
- // static_cast(drawBufferResolution.x) / static_cast(windowSize.x),
- // static_cast(drawBufferResolution.y) / static_cast(windowSize.y)
- //);
-
- //LINFO("DrawBufferResolution: " << std::to_string(drawBufferResolution));
- //LINFO("Window Size: " << std::to_string(windowSize));
double dt = _windowWrapper->averageDeltaTime();
_gui->startFrame(
static_cast(dt),
glm::vec2(windowSize),
- glm::vec2(renderingSize),
+ _windowWrapper->dpiScaling(),
mousePosition,
mouseButtons
);
diff --git a/src/engine/wrapper/sgctwindowwrapper.cpp b/src/engine/wrapper/sgctwindowwrapper.cpp
index 965ff9b184..0b8b1d76f1 100644
--- a/src/engine/wrapper/sgctwindowwrapper.cpp
+++ b/src/engine/wrapper/sgctwindowwrapper.cpp
@@ -120,6 +120,13 @@ glm::ivec2 SGCTWindowWrapper::currentDrawBufferResolution() const {
}
throw WindowWrapperException("No viewport available");
}
+
+glm::vec2 SGCTWindowWrapper::dpiScaling() const {
+ return glm::vec2(
+ sgct::Engine::instance()->getCurrentWindowPtr()->getXScale(),
+ sgct::Engine::instance()->getCurrentWindowPtr()->getYScale()
+ );
+}
int SGCTWindowWrapper::currentNumberOfAaSamples() const {
return sgct::Engine::instance()->getCurrentWindowPtr()->getNumberOfAASamples();
diff --git a/src/engine/wrapper/windowwrapper.cpp b/src/engine/wrapper/windowwrapper.cpp
index 6a2ac79009..436c34d87f 100644
--- a/src/engine/wrapper/windowwrapper.cpp
+++ b/src/engine/wrapper/windowwrapper.cpp
@@ -108,6 +108,10 @@ glm::ivec2 WindowWrapper::currentWindowResolution() const {
glm::ivec2 WindowWrapper::currentDrawBufferResolution() const {
return currentWindowSize();
}
+
+glm::vec2 WindowWrapper::dpiScaling() const {
+ return glm::vec2(1.f);
+}
int WindowWrapper::currentNumberOfAaSamples() const {
return 1;
From f9b7953ebf6d5587799191a1cf6304aeb4ebab83 Mon Sep 17 00:00:00 2001
From: Alexander Bock
Date: Mon, 24 Oct 2016 14:31:30 +0200
Subject: [PATCH 03/43] Updated Ghoul repository (Closing #145)
---
ext/ghoul | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ext/ghoul b/ext/ghoul
index f9e1207470..8fdd1127c2 160000
--- a/ext/ghoul
+++ b/ext/ghoul
@@ -1 +1 @@
-Subproject commit f9e12074702627b1feef9a09670270fed511ff5a
+Subproject commit 8fdd1127c2127d59faad893e04d5f3e481da5255
From b95c80bb40d67e03fd55cb71096a377e09a616c8 Mon Sep 17 00:00:00 2001
From: Alexander Bock
Date: Wed, 26 Oct 2016 14:44:42 +0200
Subject: [PATCH 04/43] Return the correct window size for side-by-side stereo
setting (closing #110)
---
src/engine/wrapper/sgctwindowwrapper.cpp | 28 +++++++++++++++---------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/src/engine/wrapper/sgctwindowwrapper.cpp b/src/engine/wrapper/sgctwindowwrapper.cpp
index 0b8b1d76f1..d70db6044d 100644
--- a/src/engine/wrapper/sgctwindowwrapper.cpp
+++ b/src/engine/wrapper/sgctwindowwrapper.cpp
@@ -90,19 +90,27 @@ uint32_t SGCTWindowWrapper::mouseButtons(int maxNumber) const {
}
glm::ivec2 SGCTWindowWrapper::currentWindowSize() const {
- //return glm::ivec2(sgct::Engine::instance()->getCurrentWindowPtr()->getXResolution(),
- // sgct::Engine::instance()->getCurrentWindowPtr()->getYResolution());
-
- return glm::ivec2(sgct::Engine::instance()->getCurrentWindowPtr()->getXResolution(),
- sgct::Engine::instance()->getCurrentWindowPtr()->getYResolution());
+ auto window = sgct::Engine::instance()->getCurrentWindowPtr();
+ switch (window->getStereoMode()) {
+ case sgct::SGCTWindow::Side_By_Side_Stereo:
+ case sgct::SGCTWindow::Side_By_Side_Inverted_Stereo:
+ return glm::ivec2(
+ window->getXResolution() / 2,
+ window->getYResolution());
+ case sgct::SGCTWindow::Top_Bottom_Stereo:
+ case sgct::SGCTWindow::Top_Bottom_Inverted_Stereo:
+ return glm::ivec2(
+ window->getXResolution(),
+ window->getYResolution() / 2);
+ default:
+ return glm::ivec2(
+ window->getXResolution(),
+ window->getYResolution());
+ }
}
glm::ivec2 SGCTWindowWrapper::currentWindowResolution() const {
- //int width, height;
- //auto window = sgct::Engine::instance()->getCurrentWindowPtr()->getWindowHandle();
- //glfwGetFramebufferSize(window, &width, &height);
- //return glm::ivec2(width, height);
-
+ auto window = sgct::Engine::instance()->getCurrentWindowPtr();
int x, y;
sgct::Engine::instance()->getCurrentWindowPtr()->getFinalFBODimensions(x, y);
return glm::ivec2(x, y);
From db4524d2acc48941ae45d9d903f28f5d007cd4fc Mon Sep 17 00:00:00 2001
From: Alexander Bock
Date: Wed, 26 Oct 2016 16:47:42 +0200
Subject: [PATCH 05/43] - Restructure Rotation classes to make the base class
store the rotation to remove an additional virtual function - Add Matrix
verifiers - Add documentation to StaticRotation and SpiceRotation
---
include/openspace/documentation/verifier.h | 126 ++++++++
include/openspace/documentation/verifier.inl | 63 ++++
include/openspace/scene/rotation.h | 4 +-
modules/base/basemodule.cpp | 1 +
modules/base/rotation/spicerotation.cpp | 112 ++++---
modules/base/rotation/spicerotation.h | 12 +-
modules/base/rotation/staticrotation.cpp | 69 ++++-
modules/base/rotation/staticrotation.h | 17 +-
src/documentation/core_registration.cpp | 4 +-
src/documentation/verifier.cpp | 10 +
src/scene/rotation.cpp | 4 +
tests/test_documentation.inl | 297 +++++++++++++++++++
12 files changed, 650 insertions(+), 69 deletions(-)
diff --git a/include/openspace/documentation/verifier.h b/include/openspace/documentation/verifier.h
index 1adcc9b140..c28cbd030e 100644
--- a/include/openspace/documentation/verifier.h
+++ b/include/openspace/documentation/verifier.h
@@ -235,6 +235,100 @@ struct Vector4Verifier : public TemplateVerifier>, public VectorVe
std::string type() const override;
};
+//----------------------------------------------------------------------------------------
+// Matrix verifiers
+//----------------------------------------------------------------------------------------
+
+/**
+* This struct is the base class for all Verifier%s that check for \c glm matrix types.
+* The template parameter for the subclasses is the containing type, not the full matrix
+* type. For example to check for glm::dmat4x3, one would create a
+* Matrix4x3Verifier.
+*/
+struct MatrixVerifier {};
+
+/**
+* This Verifier checks whether the value is of type glm::mat2x2
+*/
+template
+struct Matrix2x2Verifier :
+ public TemplateVerifier>, public MatrixVerifier
+{
+ std::string type() const override;
+};
+
+/**
+* This Verifier checks whether the value is of type glm::mat2x3
+*/
+template
+struct Matrix2x3Verifier :
+ public TemplateVerifier>, public MatrixVerifier {
+ std::string type() const override;
+};
+
+/**
+* This Verifier checks whether the value is of type glm::mat2x4
+*/
+template
+struct Matrix2x4Verifier :
+ public TemplateVerifier>, public MatrixVerifier {
+ std::string type() const override;
+};
+
+/**
+* This Verifier checks whether the value is of type glm::mat3x2
+*/
+template
+struct Matrix3x2Verifier :
+ public TemplateVerifier>, public MatrixVerifier {
+ std::string type() const override;
+};
+
+/**
+* This Verifier checks whether the value is of type glm::mat3x3
+*/
+template
+struct Matrix3x3Verifier :
+ public TemplateVerifier>, public MatrixVerifier {
+ std::string type() const override;
+};
+
+/**
+* This Verifier checks whether the value is of type glm::mat3x4
+*/
+template
+struct Matrix3x4Verifier :
+ public TemplateVerifier>, public MatrixVerifier {
+ std::string type() const override;
+};
+
+/**
+* This Verifier checks whether the value is of type glm::mat4x2
+*/
+template
+struct Matrix4x2Verifier :
+ public TemplateVerifier>, public MatrixVerifier {
+ std::string type() const override;
+};
+
+/**
+* This Verifier checks whether the value is of type glm::mat4x3
+*/
+template
+struct Matrix4x3Verifier :
+ public TemplateVerifier>, public MatrixVerifier {
+ std::string type() const override;
+};
+
+/**
+* This Verifier checks whether the value is of type glm::mat4x4
+*/
+template
+struct Matrix4x4Verifier :
+ public TemplateVerifier>, public MatrixVerifier {
+ std::string type() const override;
+};
+
//----------------------------------------------------------------------------------------
// Operator verifiers
//----------------------------------------------------------------------------------------
@@ -840,6 +934,28 @@ using IntVector4Verifier = Vector4Verifier;
/// A short-hand definition for a Verifier checking for glm::dvec4
using DoubleVector4Verifier = Vector4Verifier;
+/// A short-hand definition for a Verifier checking for glm::dmat2x2
+using DoubleMatrix2x2Verifier = Matrix2x2Verifier;
+using DoubleMatrix2Verifier = DoubleMatrix2x2Verifier;
+/// A short-hand definition for a Verifier checking for glm::dmat2x3
+using DoubleMatrix2x3Verifier = Matrix2x3Verifier;
+/// A short-hand definition for a Verifier checking for glm::dmat2x4
+using DoubleMatrix2x4Verifier = Matrix2x4Verifier;
+/// A short-hand definition for a Verifier checking for glm::dmat3x2
+using DoubleMatrix3x2Verifier = Matrix3x2Verifier;
+/// A short-hand definition for a Verifier checking for glm::dmat3x3
+using DoubleMatrix3x3Verifier = Matrix3x3Verifier;
+using DoubleMatrix3Verifier = DoubleMatrix3x3Verifier;
+/// A short-hand definition for a Verifier checking for glm::dmat3x4
+using DoubleMatrix3x4Verifier = Matrix3x4Verifier;
+/// A short-hand definition for a Verifier checking for glm::dmat4x2
+using DoubleMatrix4x2Verifier = Matrix4x2Verifier;
+/// A short-hand definition for a Verifier checking for glm::dmat4x3
+using DoubleMatrix4x3Verifier = Matrix4x3Verifier;
+/// A short-hand definition for a Verifier checking for glm::dmat4x4
+using DoubleMatrix4x4Verifier = Matrix4x4Verifier;
+using DoubleMatrix4Verifier = DoubleMatrix4x4Verifier;
+
/// A short-hand definition for a LessVerifier with a type check for \c int
using IntLessVerifier = LessVerifier;
/// A short-hand definition for a LessVerifier with a type check for \c double
@@ -936,6 +1052,16 @@ extern template struct Vector4Verifier;
extern template struct Vector4Verifier;
extern template struct Vector4Verifier;
+extern template struct Matrix2x2Verifier;
+extern template struct Matrix2x3Verifier;
+extern template struct Matrix2x4Verifier;
+extern template struct Matrix3x2Verifier;
+extern template struct Matrix3x3Verifier;
+extern template struct Matrix3x4Verifier;
+extern template struct Matrix4x2Verifier;
+extern template struct Matrix4x3Verifier;
+extern template struct Matrix4x4Verifier;
+
extern template struct LessVerifier;
extern template struct LessVerifier;
extern template struct LessEqualVerifier;
diff --git a/include/openspace/documentation/verifier.inl b/include/openspace/documentation/verifier.inl
index deaa984b3d..8df5f6e3f6 100644
--- a/include/openspace/documentation/verifier.inl
+++ b/include/openspace/documentation/verifier.inl
@@ -74,6 +74,69 @@ std::string Vector4Verifier::type() const {
return "Vector4<"s + typeid(T).name() + ">";
}
+template
+std::string Matrix2x2Verifier::type() const {
+ using namespace std::string_literals;
+
+ return "Matrix2x2<"s + typeid(T).name() + ">";
+}
+
+template
+std::string Matrix2x3Verifier::type() const {
+ using namespace std::string_literals;
+
+ return "Matrix2x3<"s + typeid(T).name() + ">";
+}
+
+template
+std::string Matrix2x4Verifier::type() const {
+ using namespace std::string_literals;
+
+ return "Matrix2x4<"s + typeid(T).name() + ">";
+}
+
+template
+std::string Matrix3x2Verifier::type() const {
+ using namespace std::string_literals;
+
+ return "Matrix3x2<"s + typeid(T).name() + ">";
+}
+
+template
+std::string Matrix3x3Verifier::type() const {
+ using namespace std::string_literals;
+
+ return "Matrix3x3<"s + typeid(T).name() + ">";
+}
+
+template
+std::string Matrix3x4Verifier::type() const {
+ using namespace std::string_literals;
+
+ return "Matrix3x4<"s + typeid(T).name() + ">";
+}
+
+template
+std::string Matrix4x2Verifier::type() const {
+ using namespace std::string_literals;
+
+ return "Matrix4x2<"s + typeid(T).name() + ">";
+}
+
+template
+std::string Matrix4x3Verifier::type() const {
+ using namespace std::string_literals;
+
+ return "Matrix4x3<"s + typeid(T).name() + ">";
+}
+
+template
+std::string Matrix4x4Verifier::type() const {
+ using namespace std::string_literals;
+
+ return "Matrix4x4<"s + typeid(T).name() + ">";
+}
+
template
OperatorVerifier::OperatorVerifier(typename T::Type value)
: value(std::move(value))
diff --git a/include/openspace/scene/rotation.h b/include/openspace/scene/rotation.h
index 42e35bd3bd..de12533517 100644
--- a/include/openspace/scene/rotation.h
+++ b/include/openspace/scene/rotation.h
@@ -39,13 +39,15 @@ public:
Rotation(const ghoul::Dictionary& dictionary);
virtual ~Rotation();
virtual bool initialize();
- virtual const glm::dmat3& matrix() const = 0;
+ const glm::dmat3& matrix() const;
virtual void update(const UpdateData& data);
static openspace::Documentation Documentation();
protected:
Rotation();
+
+ glm::dmat3 _matrix;
};
} // namespace openspace
diff --git a/modules/base/basemodule.cpp b/modules/base/basemodule.cpp
index d5a0d62923..f52e3acd0f 100644
--- a/modules/base/basemodule.cpp
+++ b/modules/base/basemodule.cpp
@@ -136,6 +136,7 @@ void BaseModule::internalInitialize() {
std::vector BaseModule::documentations() const {
return {
+ SpiceRotation::Documentation(),
StaticScale::Documentation(),
StaticTranslation::Documentation(),
SpiceTranslation::Documentation()
diff --git a/modules/base/rotation/spicerotation.cpp b/modules/base/rotation/spicerotation.cpp
index 709292554d..a1adcdc2fa 100644
--- a/modules/base/rotation/spicerotation.cpp
+++ b/modules/base/rotation/spicerotation.cpp
@@ -24,6 +24,8 @@
#include
+#include
+
#include
#include
@@ -38,56 +40,90 @@ namespace {
namespace openspace {
-SpiceRotation::SpiceRotation(const ghoul::Dictionary& dictionary)
- : _sourceFrame("")
- , _destinationFrame("")
- , _rotationMatrix(1.0)
- , _kernelsLoadedSuccessfully(true)
-{
- const bool hasSourceFrame = dictionary.getValue(KeySourceFrame, _sourceFrame);
- if (!hasSourceFrame)
- LERROR("SpiceRotation does not contain the key '" << KeySourceFrame << "'");
-
- const bool hasDestinationFrame = dictionary.getValue(KeyDestinationFrame, _destinationFrame);
- if (!hasDestinationFrame)
- LERROR("SpiceRotation does not contain the key '" << KeyDestinationFrame << "'");
-
- ghoul::Dictionary kernels;
- dictionary.getValue(KeyKernels, kernels);
- for (size_t i = 1; i <= kernels.size(); ++i) {
- std::string kernel;
- bool success = kernels.getValue(std::to_string(i), kernel);
- if (!success)
- LERROR("'" << KeyKernels << "' has to be an array-style table");
-
- try {
- SpiceManager::ref().loadKernel(kernel);
- _kernelsLoadedSuccessfully = true;
+Documentation SpiceRotation::Documentation() {
+ using namespace openspace::documentation;
+ return {
+ "Spice Rotation",
+ "base_transform_rotation_spice",
+ {
+ {
+ "Type",
+ new StringEqualVerifier("SpiceRotation"),
+ "",
+ Optional::No
+ },
+ {
+ KeySourceFrame,
+ new StringAnnotationVerifier("A valid SPICE NAIF name or integer"),
+ "The source frame that is used as the basis for the coordinate "
+ "transformation. This has to be a valid SPICE name.",
+ Optional::No
+ },
+ {
+ KeyDestinationFrame,
+ new StringAnnotationVerifier("A valid SPICE NAIF name or integer"),
+ "The destination frame that is used for the coordinate transformation. "
+ "This has to be a valid SPICE name.",
+ Optional::No
+ },
+ {
+ KeyKernels,
+ new OrVerifier(
+ new TableVerifier({
+ { "*", new StringVerifier }
+ }),
+ new StringVerifier
+ ),
+ "A single kernel or list of kernels that this SpiceTranslation depends "
+ "on. All provided kernels will be loaded before any other operation is "
+ "performed.",
+ Optional::Yes
+ }
}
- catch (const SpiceManager::SpiceException& e) {
- LERROR("Could not load SPICE kernel: " << e.what());
- _kernelsLoadedSuccessfully = false;
+ };
+}
+
+SpiceRotation::SpiceRotation(const ghoul::Dictionary& dictionary)
+ : _sourceFrame("source", "Source", "")
+ , _destinationFrame("destination", "Destination", "")
+{
+ documentation::testSpecificationAndThrow(
+ Documentation(),
+ dictionary,
+ "SpiceRotation"
+ );
+
+ _sourceFrame = dictionary.value(KeySourceFrame);
+ _destinationFrame = dictionary.value(KeyDestinationFrame);
+
+ if (dictionary.hasKeyAndValue(KeyKernels)) {
+ SpiceManager::ref().loadKernel(dictionary.value(KeyKernels));
+ }
+ else if (dictionary.hasKeyAndValue(KeyKernels)) {
+ ghoul::Dictionary kernels = dictionary.value(KeyKernels);
+ for (size_t i = 1; i <= kernels.size(); ++i) {
+ if (!kernels.hasKeyAndValue(std::to_string(i))) {
+ throw ghoul::RuntimeError("Kernels has to be an array-style table");
+ }
+
+ std::string kernel = kernels.value(std::to_string(i));
+ SpiceManager::ref().loadKernel(kernel);
}
}
}
-const glm::dmat3& SpiceRotation::matrix() const {
- return _rotationMatrix;
-}
-
void SpiceRotation::update(const UpdateData& data) {
- if (!_kernelsLoadedSuccessfully)
- return;
try {
- _rotationMatrix = SpiceManager::ref().positionTransformMatrix(
+ _matrix = SpiceManager::ref().positionTransformMatrix(
_sourceFrame,
_destinationFrame,
- data.time);
+ data.time
+ );
}
catch (const ghoul::RuntimeError&) {
// In case of missing coverage
- _rotationMatrix = glm::dmat3(1);
+ _matrix = glm::dmat3(1);
}
}
-} // namespace openspace
\ No newline at end of file
+} // namespace openspace
diff --git a/modules/base/rotation/spicerotation.h b/modules/base/rotation/spicerotation.h
index 034ff7fece..4c3cecf729 100644
--- a/modules/base/rotation/spicerotation.h
+++ b/modules/base/rotation/spicerotation.h
@@ -26,20 +26,22 @@
#define __SPICEROTATION_H__
#include
+#include
+#include
namespace openspace {
class SpiceRotation : public Rotation {
public:
SpiceRotation(const ghoul::Dictionary& dictionary);
- virtual const glm::dmat3& matrix() const;
+ const glm::dmat3& matrix() const;
void update(const UpdateData& data) override;
+ static openspace::Documentation Documentation();
+
private:
- std::string _sourceFrame;
- std::string _destinationFrame;
- glm::dmat3 _rotationMatrix;
- bool _kernelsLoadedSuccessfully;
+ properties::StringProperty _sourceFrame;
+ properties::StringProperty _destinationFrame;
};
} // namespace openspace
diff --git a/modules/base/rotation/staticrotation.cpp b/modules/base/rotation/staticrotation.cpp
index a009fa571e..f44e768c6e 100644
--- a/modules/base/rotation/staticrotation.cpp
+++ b/modules/base/rotation/staticrotation.cpp
@@ -24,29 +24,66 @@
#include
+#include
+
namespace {
- const std::string KeyEulerAngles = "EulerAngles";
+ const std::string KeyRotation = "Rotation";
}
namespace openspace {
+Documentation StaticRotation::Documentation() {
+ using namespace openspace::documentation;
+ return {
+ "Static Rotation",
+ "base_transform_rotation_static",
+ {
+ {
+ "Type",
+ new StringEqualVerifier("StaticRotation"),
+ "",
+ Optional::No
+ },
+ {
+ KeyRotation,
+ new OrVerifier(
+ new DoubleVector3Verifier(),
+ new DoubleMatrix3Verifier()
+ ),
+ "Stores the static rotation as either a vector containing Euler angles "
+ "or by specifiying the 3x3 rotation matrix directly",
+ Optional::No
+ }
+ },
+ Exhaustive::Yes
+ };
+}
+
+StaticRotation::StaticRotation()
+ : _rotationMatrix("rotation", "Rotation", glm::dmat3(1.0))
+{}
+
StaticRotation::StaticRotation(const ghoul::Dictionary& dictionary)
- : _rotationMatrix(1.0)
+ : StaticRotation()
{
- const bool hasEulerAngles = dictionary.hasKeyAndValue(KeyEulerAngles);
- if (hasEulerAngles) {
- glm::dvec3 tmp;
- dictionary.getValue(KeyEulerAngles, tmp);
- _rotationMatrix = glm::mat3_cast(glm::dquat(tmp));
+ documentation::testSpecificationAndThrow(
+ Documentation(),
+ dictionary,
+ "StaticRotation"
+ );
+
+
+ if (dictionary.hasKeyAndValue(KeyRotation)) {
+ _rotationMatrix = glm::mat3_cast(
+ glm::dquat(dictionary.value(KeyRotation))
+ );
}
+ else {
+ // Must be glm::dmat3 due to specification restriction
+ _rotationMatrix = dictionary.value(KeyRotation);
+ }
+
+ _rotationMatrix.onChange([this]() { _matrix = _rotationMatrix; });
}
-StaticRotation::~StaticRotation() {}
-
-const glm::dmat3& StaticRotation::matrix() const {
- return _rotationMatrix;
-}
-
-void StaticRotation::update(const UpdateData&) {}
-
-} // namespace openspace
\ No newline at end of file
+} // namespace openspace
diff --git a/modules/base/rotation/staticrotation.h b/modules/base/rotation/staticrotation.h
index 4474081057..8df5c8637e 100644
--- a/modules/base/rotation/staticrotation.h
+++ b/modules/base/rotation/staticrotation.h
@@ -27,17 +27,20 @@
#include
+#include
+#include
+
namespace openspace {
-class StaticRotation: public Rotation {
+class StaticRotation : public Rotation {
public:
- StaticRotation(const ghoul::Dictionary& dictionary
- = ghoul::Dictionary());
- virtual ~StaticRotation();
- virtual const glm::dmat3& matrix() const;
- virtual void update(const UpdateData& data) override;
+ StaticRotation();
+ StaticRotation(const ghoul::Dictionary& dictionary);
+
+ static openspace::Documentation Documentation();
+
private:
- glm::dmat3 _rotationMatrix;
+ properties::DMat3Property _rotationMatrix;
};
} // namespace openspace
diff --git a/src/documentation/core_registration.cpp b/src/documentation/core_registration.cpp
index 8777700213..4f87a5ee20 100644
--- a/src/documentation/core_registration.cpp
+++ b/src/documentation/core_registration.cpp
@@ -35,11 +35,11 @@
#include
#include
#include
-#include
#include
#include
#include
#include
+#include
#include
#include
#include
@@ -54,7 +54,6 @@ namespace openspace {
void registerCoreClasses(documentation::DocumentationEngine& engine) {
engine.addDocumentation(ConfigurationManager::Documentation());
- engine.addDocumentation(Translation::Documentation());
engine.addDocumentation(Mission::Documentation());
engine.addDocumentation(Renderable::Documentation());
engine.addDocumentation(Rotation::Documentation());
@@ -63,6 +62,7 @@ void registerCoreClasses(documentation::DocumentationEngine& engine) {
engine.addDocumentation(SceneGraphNode::Documentation());
engine.addDocumentation(ScreenSpaceRenderable::Documentation());
engine.addDocumentation(TimeRange::Documentation());
+ engine.addDocumentation(Translation::Documentation());
}
void registerCoreClasses(scripting::ScriptEngine& engine) {
diff --git a/src/documentation/verifier.cpp b/src/documentation/verifier.cpp
index 4c68386f7c..540f9b9439 100644
--- a/src/documentation/verifier.cpp
+++ b/src/documentation/verifier.cpp
@@ -41,6 +41,16 @@ template struct Vector4Verifier;
template struct Vector4Verifier;
template struct Vector4Verifier;
+template struct Matrix2x2Verifier;
+template struct Matrix2x3Verifier;
+template struct Matrix2x4Verifier;
+template struct Matrix3x2Verifier;
+template struct Matrix3x3Verifier;
+template struct Matrix3x4Verifier;
+template struct Matrix4x2Verifier;
+template struct Matrix4x3Verifier;
+template struct Matrix4x4Verifier;
+
template struct LessVerifier;
template struct LessVerifier;
template struct LessEqualVerifier;
diff --git a/src/scene/rotation.cpp b/src/scene/rotation.cpp
index a4d77d54ff..e098274235 100644
--- a/src/scene/rotation.cpp
+++ b/src/scene/rotation.cpp
@@ -79,6 +79,10 @@ bool Rotation::initialize() {
return true;
}
+const glm::dmat3& Rotation::matrix() const {
+ return _matrix;
+}
+
void Rotation::update(const UpdateData& data) {}
} // namespace openspace
\ No newline at end of file
diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl
index da672ca414..07e256f068 100644
--- a/tests/test_documentation.inl
+++ b/tests/test_documentation.inl
@@ -2308,6 +2308,303 @@ TEST_F(DocumentationTest, DoubleVector4Verifier) {
EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
}
+TEST_F(DocumentationTest, DoubleMatrix2x2Verifier) {
+ using namespace openspace::documentation;
+
+ Documentation doc {
+ { { "a", new DoubleMatrix2x2Verifier } }
+ };
+
+ ghoul::Dictionary positive {
+ { "a", glm::dmat2x2(1.0) }
+ };
+ TestResult positiveRes = testSpecification(doc, positive);
+ EXPECT_TRUE(positiveRes.success);
+ EXPECT_EQ(0, positiveRes.offenses.size());
+
+ ghoul::Dictionary negative {
+ { "a", ghoul::Dictionary { { "1", true },{ "2", 1.0 },{ "3", "s" } } }
+ };
+ TestResult negativeRes = testSpecification(doc, negative);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+
+ ghoul::Dictionary negative2 {
+ { "a", true }
+ };
+ negativeRes = testSpecification(doc, negative2);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+}
+
+TEST_F(DocumentationTest, DoubleMatrix2x3Verifier) {
+ using namespace openspace::documentation;
+
+ Documentation doc {
+ { { "a", new DoubleMatrix2x3Verifier } }
+ };
+
+ ghoul::Dictionary positive {
+ { "a", glm::dmat2x3(1.0) }
+ };
+ TestResult positiveRes = testSpecification(doc, positive);
+ EXPECT_TRUE(positiveRes.success);
+ EXPECT_EQ(0, positiveRes.offenses.size());
+
+ ghoul::Dictionary negative {
+ { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 },{ "3", "s" } } }
+ };
+ TestResult negativeRes = testSpecification(doc, negative);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+
+ ghoul::Dictionary negative2 {
+ { "a", true }
+ };
+ negativeRes = testSpecification(doc, negative2);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+}
+
+TEST_F(DocumentationTest, DoubleMatrix2x4Verifier) {
+ using namespace openspace::documentation;
+
+ Documentation doc {
+ { { "a", new DoubleMatrix2x4Verifier } }
+ };
+
+ ghoul::Dictionary positive {
+ { "a", glm::dmat2x4(1.0) }
+ };
+ TestResult positiveRes = testSpecification(doc, positive);
+ EXPECT_TRUE(positiveRes.success);
+ EXPECT_EQ(0, positiveRes.offenses.size());
+
+ ghoul::Dictionary negative {
+ { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 },{ "3", "s" } } }
+ };
+ TestResult negativeRes = testSpecification(doc, negative);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+
+ ghoul::Dictionary negative2 {
+ { "a", true }
+ };
+ negativeRes = testSpecification(doc, negative2);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+}
+
+TEST_F(DocumentationTest, DoubleMatrix3x2Verifier) {
+ using namespace openspace::documentation;
+
+ Documentation doc {
+ { { "a", new DoubleMatrix3x2Verifier } }
+ };
+
+ ghoul::Dictionary positive {
+ { "a", glm::dmat3x2(1.0) }
+ };
+ TestResult positiveRes = testSpecification(doc, positive);
+ EXPECT_TRUE(positiveRes.success);
+ EXPECT_EQ(0, positiveRes.offenses.size());
+
+ ghoul::Dictionary negative {
+ { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 },{ "3", "s" } } }
+ };
+ TestResult negativeRes = testSpecification(doc, negative);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+
+ ghoul::Dictionary negative2 {
+ { "a", true }
+ };
+ negativeRes = testSpecification(doc, negative2);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+}
+
+TEST_F(DocumentationTest, DoubleMatrix3x3Verifier) {
+ using namespace openspace::documentation;
+
+ Documentation doc {
+ { { "a", new DoubleMatrix3x3Verifier } }
+ };
+
+ ghoul::Dictionary positive {
+ { "a", glm::dmat3x3(1.0) }
+ };
+ TestResult positiveRes = testSpecification(doc, positive);
+ EXPECT_TRUE(positiveRes.success);
+ EXPECT_EQ(0, positiveRes.offenses.size());
+
+ ghoul::Dictionary negative {
+ { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 },{ "3", "s" } } }
+ };
+ TestResult negativeRes = testSpecification(doc, negative);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+
+ ghoul::Dictionary negative2 {
+ { "a", true }
+ };
+ negativeRes = testSpecification(doc, negative2);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+}
+
+TEST_F(DocumentationTest, DoubleMatrix3x4Verifier) {
+ using namespace openspace::documentation;
+
+ Documentation doc {
+ { { "a", new DoubleMatrix3x4Verifier } }
+ };
+
+ ghoul::Dictionary positive {
+ { "a", glm::dmat3x4(1.0) }
+ };
+ TestResult positiveRes = testSpecification(doc, positive);
+ EXPECT_TRUE(positiveRes.success);
+ EXPECT_EQ(0, positiveRes.offenses.size());
+
+ ghoul::Dictionary negative {
+ { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 },{ "3", "s" } } }
+ };
+ TestResult negativeRes = testSpecification(doc, negative);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+
+ ghoul::Dictionary negative2 {
+ { "a", true }
+ };
+ negativeRes = testSpecification(doc, negative2);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+}
+
+TEST_F(DocumentationTest, DoubleMatrix4x2Verifier) {
+ using namespace openspace::documentation;
+
+ Documentation doc {
+ { { "a", new DoubleMatrix4x2Verifier } }
+ };
+
+ ghoul::Dictionary positive {
+ { "a", glm::dmat4x2(1.0) }
+ };
+ TestResult positiveRes = testSpecification(doc, positive);
+ EXPECT_TRUE(positiveRes.success);
+ EXPECT_EQ(0, positiveRes.offenses.size());
+
+ ghoul::Dictionary negative {
+ { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 },{ "3", "s" } } }
+ };
+ TestResult negativeRes = testSpecification(doc, negative);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+
+ ghoul::Dictionary negative2 {
+ { "a", true }
+ };
+ negativeRes = testSpecification(doc, negative2);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+}
+
+TEST_F(DocumentationTest, DoubleMatrix4x3Verifier) {
+ using namespace openspace::documentation;
+
+ Documentation doc {
+ { { "a", new DoubleMatrix4x3Verifier } }
+ };
+
+ ghoul::Dictionary positive {
+ { "a", glm::dmat4x3(1.0) }
+ };
+ TestResult positiveRes = testSpecification(doc, positive);
+ EXPECT_TRUE(positiveRes.success);
+ EXPECT_EQ(0, positiveRes.offenses.size());
+
+ ghoul::Dictionary negative {
+ { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 },{ "3", "s" } } }
+ };
+ TestResult negativeRes = testSpecification(doc, negative);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+
+ ghoul::Dictionary negative2 {
+ { "a", true }
+ };
+ negativeRes = testSpecification(doc, negative2);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+}
+
+TEST_F(DocumentationTest, DoubleMatrix4x4Verifier) {
+ using namespace openspace::documentation;
+
+ Documentation doc {
+ { { "a", new DoubleMatrix4x4Verifier } }
+ };
+
+ ghoul::Dictionary positive {
+ { "a", glm::dmat4x4(1.0) }
+ };
+ TestResult positiveRes = testSpecification(doc, positive);
+ EXPECT_TRUE(positiveRes.success);
+ EXPECT_EQ(0, positiveRes.offenses.size());
+
+ ghoul::Dictionary negative {
+ { "a", ghoul::Dictionary{ { "1", true },{ "2", 1.0 },{ "3", "s" } } }
+ };
+ TestResult negativeRes = testSpecification(doc, negative);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+
+ ghoul::Dictionary negative2 {
+ { "a", true }
+ };
+ negativeRes = testSpecification(doc, negative2);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("a", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+}
+
TEST_F(DocumentationTest, DeprecatedVerifier) {
using namespace openspace::documentation;
using namespace std::string_literals;
From f03073508aeff4318caa3e6fdf6e08891d9b19d4 Mon Sep 17 00:00:00 2001
From: Alexander Bock
Date: Wed, 26 Oct 2016 16:58:53 +0200
Subject: [PATCH 06/43] Add the reporting of the actual documentation in the
DocumentationEngine
---
src/documentation/documentationengine.cpp | 11 +++++++++++
src/engine/configurationmanager_doc.inl | 7 ++++---
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/src/documentation/documentationengine.cpp b/src/documentation/documentationengine.cpp
index 0bcab0e7c3..0181f0178d 100644
--- a/src/documentation/documentationengine.cpp
+++ b/src/documentation/documentationengine.cpp
@@ -83,6 +83,7 @@ std::string generateTextDocumentation(const Documentation& d, int& indentLevel)
result += indentMessage("Key", (p.key == "*") ? p.key : "\"" + p.key + "\"");
result += indentMessage("Optional", (p.optional ? "true" : "false"));
result += indentMessage("Type", p.verifier->type());
+ result += indentMessage("Documentation", p.documentation);
TableVerifier* tv = dynamic_cast(p.verifier.get());
ReferencingVerifier* rv = dynamic_cast(p.verifier.get());
@@ -134,6 +135,7 @@ std::string generateJsonDocumentation(const Documentation& d) {
result << "\"key\": \"" << p.key << "\",";
result << "\"optional\": " << (p.optional ? "true" : "false") << ",";
result << "\"type\": \"" << p.verifier->type() << "\",";
+ result << "\"documentation\": \"" << p.documentation << "\",";
TableVerifier* tv = dynamic_cast(p.verifier.get());
ReferencingVerifier* rv = dynamic_cast(p.verifier.get());
@@ -167,6 +169,7 @@ std::string generateJsonDocumentation(const Documentation& d) {
if (&p != &d.entries.back()) {
result << ", ";
}
+
}
result << ']';
@@ -186,6 +189,7 @@ std::string generateHtmlDocumentation(const Documentation& d) {
<< "\t\t | \n"
<< "\t\t" << p.key << " | \n"
<< "\t\t" << (p.optional ? "Optional" : "Required") << " | \n"
+ << "\t\t" << p.documentation << " | \n"
<< "\t\t" << p.verifier->type() << " | \n";
TableVerifier* tv = dynamic_cast(p.verifier.get());
@@ -366,6 +370,13 @@ void DocumentationEngine::writeDocumentation(const std::string& f, const std::st
}
void DocumentationEngine::addDocumentation(Documentation doc) {
+ for (const DocumentationEntry& e : doc.entries) {
+ ghoul_assert(
+ e.documentation.find('"') == std::string::npos,
+ "Documentation cannot contain \" character"
+ );
+ }
+
if (doc.id.empty()) {
_documentations.push_back(std::move(doc));
}
diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl
index 3f1b33c058..ea60c236cf 100644
--- a/src/engine/configurationmanager_doc.inl
+++ b/src/engine/configurationmanager_doc.inl
@@ -42,7 +42,8 @@ Documentation ConfigurationManager::Documentation() {
{
ConfigurationManager::KeyConfigScene,
new StringAnnotationVerifier(
- "A valid scene file as described in the Scene documentation"),
+ "A valid scene file as described in the Scene documentation"
+ ),
"The scene description that is used to populate the application after "
"startup. The scene determines which objects are loaded, the startup "
"time and other scene-specific settings. More information is provided in "
@@ -303,8 +304,8 @@ Documentation ConfigurationManager::Documentation() {
}),
"The method for scaling the onscreen text in the window. As the resolution "
"of the rendering can be different from the size of the window, the onscreen "
- "text can either be scaled according to the window size (\"window\"), or the "
- "rendering resolution (\"framebuffer\"). This value defaults to \"window\".",
+ "text can either be scaled according to the window size ('window'), or the "
+ "rendering resolution ('framebuffer'). This value defaults to 'window'.",
Optional::Yes
},
{
From 22847655be9912e2354e78e1188f3175e0ca0a37 Mon Sep 17 00:00:00 2001
From: Emil Axelsson
Date: Thu, 27 Oct 2016 15:24:06 +0200
Subject: [PATCH 07/43] Add Saturn's rings to mod file
---
data/scene/saturn/saturn.mod | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/data/scene/saturn/saturn.mod b/data/scene/saturn/saturn.mod
index ac59c3d9c9..9bfd690438 100644
--- a/data/scene/saturn/saturn.mod
+++ b/data/scene/saturn/saturn.mod
@@ -46,6 +46,17 @@ return {
},
},
},
+ {
+ Name = "SaturnRings",
+ Parent = "Saturn",
+ Renderable = {
+ Type = "RenderableRings",
+ Frame = "IAU_SATURN",
+ Texture = "textures/saturn_rings.png",
+ Size = { 0.140220, 9.0 }
+ },
+
+ },
-- SaturnTrail module
{
Name = "SaturnTrail",
From 4ce3be9e8cea2f4c5c8f13b21ec23cda0d329797 Mon Sep 17 00:00:00 2001
From: Alexander Bock
Date: Thu, 27 Oct 2016 15:50:29 +0200
Subject: [PATCH 08/43] Add a Verifier for a list of Strings to replace a more
cumbersome expression
---
include/openspace/documentation/verifier.h | 13 +++++
src/documentation/verifier.cpp | 8 +++
src/engine/configurationmanager_doc.inl | 14 ++----
tests/test_documentation.inl | 57 ++++++++++++++++++++++
4 files changed, 82 insertions(+), 10 deletions(-)
diff --git a/include/openspace/documentation/verifier.h b/include/openspace/documentation/verifier.h
index c28cbd030e..bc8dd451b7 100644
--- a/include/openspace/documentation/verifier.h
+++ b/include/openspace/documentation/verifier.h
@@ -199,6 +199,19 @@ struct TableVerifier : public TemplateVerifier {
Exhaustive exhaustive;
};
+/**
+ * A Verifier that checks whether all values contained in a Table are of type \c string.
+ */
+struct StringListVerifier : public TableVerifier {
+ /**
+ * Constructor for a StringListVerifier.
+ * \param elementDocumentation The documentation for each string in the list
+ */
+ StringListVerifier(std::string elementDocumentation = "");
+
+ std::string type() const override;
+};
+
//----------------------------------------------------------------------------------------
// Vector verifiers
//----------------------------------------------------------------------------------------
diff --git a/src/documentation/verifier.cpp b/src/documentation/verifier.cpp
index 540f9b9439..28b83f13d1 100644
--- a/src/documentation/verifier.cpp
+++ b/src/documentation/verifier.cpp
@@ -198,6 +198,14 @@ std::string TableVerifier::type() const {
return "Table";
}
+StringListVerifier::StringListVerifier(std::string elementDocumentation)
+ : TableVerifier({{ "*", new StringVerifier, std::move(elementDocumentation) }})
+{}
+
+std::string StringListVerifier::type() const {
+ return "List of strings";
+}
+
ReferencingVerifier::ReferencingVerifier(std::string id)
: identifier(std::move(id))
{
diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl
index ea60c236cf..4e06d9dcef 100644
--- a/src/engine/configurationmanager_doc.inl
+++ b/src/engine/configurationmanager_doc.inl
@@ -51,9 +51,7 @@ Documentation ConfigurationManager::Documentation() {
},
{
ConfigurationManager::KeyPaths,
- new TableVerifier({
- { "*", new StringVerifier }
- }),
+ new StringListVerifier,
"A list of paths that are automatically registered with the file system. "
"If a key X is used in the table, it is then useable by referencing ${X} "
"in all other configuration files or scripts.",
@@ -61,9 +59,7 @@ Documentation ConfigurationManager::Documentation() {
},
{
ConfigurationManager::KeyFonts,
- new TableVerifier({
- { "*", new StringVerifier, "Font paths loadable by FreeType" }
- }),
+ new StringListVerifier("Font paths loadable by FreeType"),
"A list of all fonts that will automatically be loaded on startup. Each "
"key-value pair contained in the table will become the name and the file "
"for a font.",
@@ -76,7 +72,7 @@ Documentation ConfigurationManager::Documentation() {
ConfigurationManager::PartLogLevel,
new StringInListVerifier(
// List from logmanager.cpp::levelFromString
- {"Debug", "Info", "Warning", "Error", "Fatal", "None" }
+ { "Debug", "Info", "Warning", "Error", "Fatal", "None" }
),
"The severity of log messages that will be displayed. Only "
"messages of the selected level or higher will be displayed. All "
@@ -312,9 +308,7 @@ Documentation ConfigurationManager::Documentation() {
ConfigurationManager::KeyDownloadRequestURL,
new OrVerifier(
new StringVerifier,
- new TableVerifier({
- { "*", new StringVerifier }
- })
+ new StringListVerifier
),
"The URL from which files will be downloaded by the Launcher. This can "
"either be a single URL or a list of possible URLs from which the "
diff --git a/tests/test_documentation.inl b/tests/test_documentation.inl
index 07e256f068..c14af8d1df 100644
--- a/tests/test_documentation.inl
+++ b/tests/test_documentation.inl
@@ -336,6 +336,63 @@ TEST_F(DocumentationTest, TableVerifierType) {
EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[0].reason);
}
+TEST_F(DocumentationTest, StringListVerifierType) {
+ using namespace openspace::documentation;
+ using namespace std::string_literals;
+
+ Documentation doc {
+ { { "StringList", new StringListVerifier } }
+ };
+
+ ghoul::Dictionary positive {
+ {
+ "StringList",
+ ghoul::Dictionary {
+ { "1", "a"s },
+ { "2", "b"s },
+ { "3", "c"s }
+ }
+ }
+ };
+ TestResult positiveRes = testSpecification(doc, positive);
+ EXPECT_TRUE(positiveRes.success);
+ EXPECT_EQ(0, positiveRes.offenses.size());
+
+ ghoul::Dictionary negative {
+ { "StringList", 0 }
+ };
+ TestResult negativeRes = testSpecification(doc, negative);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("StringList", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+
+ ghoul::Dictionary negative2 {
+ {
+ "StringList",
+ ghoul::Dictionary {
+ { "1", "a"s },
+ { "2", "b"s },
+ { "3", 2.0 }
+ }
+ }
+ };
+ negativeRes = testSpecification(doc, negative2);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("StringList.3", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
+
+ ghoul::Dictionary negativeExist {
+ { "StringList2", ghoul::Dictionary{} }
+ };
+ negativeRes = testSpecification(doc, negativeExist);
+ EXPECT_FALSE(negativeRes.success);
+ ASSERT_EQ(1, negativeRes.offenses.size());
+ EXPECT_EQ("StringList", negativeRes.offenses[0].offender);
+ EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[0].reason);
+}
+
TEST_F(DocumentationTest, MixedVerifiers) {
using namespace openspace::documentation;
using namespace std::string_literals;
From 73e6fcf865c1df06081b23ba3fd36c4a3dc6c108 Mon Sep 17 00:00:00 2001
From: Emil Axelsson
Date: Thu, 27 Oct 2016 17:09:56 +0200
Subject: [PATCH 09/43] Sort documentation sections, fix json parse error for
keybindings and add detailed documentation to html output
---
data/web/common/style.css | 12 ++++++++++++
data/web/documentation/documentation.hbs | 3 ++-
data/web/documentation/script.js | 4 ++++
data/web/factories/script.js | 4 ++++
data/web/keybindings/keybinding.hbs | 4 ++--
data/web/keybindings/script.js | 4 ++++
data/web/luascripting/script.js | 4 ++++
data/web/properties/script.js | 4 ++++
src/interaction/interactionhandler.cpp | 4 ++--
9 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/data/web/common/style.css b/data/web/common/style.css
index cf497440ad..ac82e9fe77 100644
--- a/data/web/common/style.css
+++ b/data/web/common/style.css
@@ -30,6 +30,18 @@
background-color: #fff;
}
+.documentation-item.remote-scripting {
+ border-left: 2px solid #4c1315;
+ background-color: #fcdcdc;
+ color: #4c1315;
+}
+
+.documentation-item.local-scripting {
+ border-left: 2px solid #2d4256;
+ background-color: #dcf1f9;
+ color: #2d4256;
+}
+
.documentation-type {
color: #888;
font-size: 0.8em;
diff --git a/data/web/documentation/documentation.hbs b/data/web/documentation/documentation.hbs
index 93957bdecf..2b7bbbd84d 100644
--- a/data/web/documentation/documentation.hbs
+++ b/data/web/documentation/documentation.hbs
@@ -11,7 +11,8 @@
{{/if}}
- {{description}}
+ {{description}}
+ {{documentation}}
{{#with restrictions}}
{{>documentation}}
{{/with}}
diff --git a/data/web/documentation/script.js b/data/web/documentation/script.js
index c2b320ce70..f9af37e558 100644
--- a/data/web/documentation/script.js
+++ b/data/web/documentation/script.js
@@ -18,6 +18,10 @@ window.onload = function () {
return identifier;
});
+ documentation.sort(function (a, b) {
+ return a.name < b.name ? -1 : (a.name > b.name ? 1 : 0);
+ });
+
var data = {
documentation: documentation,
version: version
diff --git a/data/web/factories/script.js b/data/web/factories/script.js
index 6334c7b2a4..4776d5656e 100644
--- a/data/web/factories/script.js
+++ b/data/web/factories/script.js
@@ -18,6 +18,10 @@ window.onload = function () {
return identifier;
});
+ factories.sort(function (a, b) {
+ return a.name < b.name ? -1 : (a.name > b.name ? 1 : 0);
+ });
+
var data = {
factories: factories,
version: version
diff --git a/data/web/keybindings/keybinding.hbs b/data/web/keybindings/keybinding.hbs
index 1b4d5414c2..29773e357e 100644
--- a/data/web/keybindings/keybinding.hbs
+++ b/data/web/keybindings/keybinding.hbs
@@ -1,9 +1,9 @@
-
+
- {{key}}
+ {{key}} {{#if remoteScripting}}Remote scripting{{else}}Local scripting{{/if}}
{{script}}
diff --git a/data/web/keybindings/script.js b/data/web/keybindings/script.js
index 149cba1892..6b4bdd444e 100644
--- a/data/web/keybindings/script.js
+++ b/data/web/keybindings/script.js
@@ -18,6 +18,10 @@ window.onload = function () {
return identifier;
});
+ keybindings.sort(function (a, b) {
+ return a.key < b.key ? -1 : (a.key > b.key ? 1 : 0);
+ });
+
var data = {
keybindings: keybindings,
version: version,
diff --git a/data/web/luascripting/script.js b/data/web/luascripting/script.js
index b43af6f884..6d43a33b07 100644
--- a/data/web/luascripting/script.js
+++ b/data/web/luascripting/script.js
@@ -18,6 +18,10 @@ window.onload = function () {
return identifier;
});
+ scripting.sort(function (a, b) {
+ return a.library < b.library ? -1 : (a.library > b.library ? 1 : 0);
+ });
+
var data = {
scripting: scripting,
version: version
diff --git a/data/web/properties/script.js b/data/web/properties/script.js
index 70f303f15f..f7302a5e0b 100644
--- a/data/web/properties/script.js
+++ b/data/web/properties/script.js
@@ -46,6 +46,10 @@ window.onload = function () {
return identifier;
});
+ propertyOwners.sort(function (a, b) {
+ return a.name < b.name ? -1 : (a.name > b.name ? 1 : 0);
+ });
+
var data = {
propertyOwners: propertyOwners,
version: version,
diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp
index 14c8ecb044..f24ced430b 100644
--- a/src/interaction/interactionhandler.cpp
+++ b/src/interaction/interactionhandler.cpp
@@ -469,8 +469,8 @@ void InteractionHandler::writeKeyboardDocumentation(const std::string& type, con
first = false;
json << "{";
json << "\"key\": \"" << std::to_string(p.first) << "\",";
- json << "\"script\": \"" << p.second.first << "\"";
- json << "\"remoteScripting\": \"" << (p.second.second ? "true" : "false") << "\"";
+ json << "\"script\": \"" << p.second.first << "\",";
+ json << "\"remoteScripting\": " << (p.second.second ? "true" : "false");
json << "}";
}
json << "]";
From 18b8aab89820d67cbf088a63caf38b91bb5f22b5 Mon Sep 17 00:00:00 2001
From: Alexander Bock
Date: Thu, 27 Oct 2016 21:45:49 +0200
Subject: [PATCH 10/43] Changes in ProjectionComponent initialization -
Remove parsing function - Make ProjectionComponent accept sub-dictionary
Remove "Rotation" key-value from RenderableModelProjection - Information
moved into RenderableFOV to do conversion between object and frame Changes in
mod files to reflect ProjectionComponent and RenderableModelProjection
changes Added Documentation to - RenderablePlanetProjection -
RenderableModelProjection - ProjectionComponent - PlanetGeometry -
ModelGeometry
---
.../newhorizons/jupiter/callisto/callisto.mod | 32 +-
.../newhorizons/jupiter/europa/europa.mod | 28 +-
.../newhorizons/jupiter/ganymede/ganymede.mod | 28 +-
data/scene/newhorizons/jupiter/io/io.mod | 28 +-
.../newhorizons/jupiter/jupiter/jupiter.mod | 91 ++---
.../newhorizons/newhorizons/newhorizons.mod | 10 +-
.../scene/newhorizons/pluto/charon/charon.mod | 35 +-
data/scene/newhorizons/pluto/pluto/pluto.mod | 196 +++++-----
data/scene/osirisrex/bennu/bennu.mod | 68 ++--
data/scene/osirisrex/osirisrex/osirisrex.mod | 3 +
data/scene/rosetta/67P/67P.mod | 76 ++--
data/scene/rosetta/rosetta/rosetta.mod | 3 +
modules/base/basemodule.cpp | 4 +-
modules/base/rendering/modelgeometry.cpp | 72 ++--
modules/base/rendering/modelgeometry.h | 4 +-
modules/base/rendering/planetgeometry.cpp | 44 ++-
modules/base/rendering/planetgeometry.h | 7 +-
modules/newhorizons/newhorizonsmodule.cpp | 8 +
modules/newhorizons/newhorizonsmodule.h | 2 +
.../newhorizons/rendering/renderablefov.cpp | 12 +
.../rendering/renderablemodelprojection.cpp | 120 +++---
.../rendering/renderablemodelprojection.h | 8 +-
.../rendering/renderableplanetprojection.cpp | 79 +++-
.../rendering/renderableplanetprojection.h | 6 +-
.../newhorizons/util/projectioncomponent.cpp | 351 +++++++++++-------
.../newhorizons/util/projectioncomponent.h | 10 +-
26 files changed, 770 insertions(+), 555 deletions(-)
diff --git a/data/scene/newhorizons/jupiter/callisto/callisto.mod b/data/scene/newhorizons/jupiter/callisto/callisto.mod
index 83e4e58c14..5454e41ed6 100644
--- a/data/scene/newhorizons/jupiter/callisto/callisto.mod
+++ b/data/scene/newhorizons/jupiter/callisto/callisto.mod
@@ -22,20 +22,22 @@ return {
Observer = "NEW HORIZONS",
Target = "CALLISTO",
Aberration = "NONE",
- AspectRatio = 2
+ AspectRatio = 2,
+
+ Instrument = {
+ Name = "NH_LORRI",
+ Method = "ELLIPSOID",
+ Aberration = "NONE",
+ Fovy = 0.2907,
+ Aspect = 1,
+ Near = 0.2,
+ Far = 10000,
+ },
+
+ PotentialTargets = {
+ "JUPITER", "IO", "EUROPA", "GANYMEDE", "CALLISTO"
+ }
},
- Instrument = {
- Name = "NH_LORRI",
- Method = "ELLIPSOID",
- Aberration = "NONE",
- Fovy = 0.2907,
- Aspect = 1,
- Near = 0.2,
- Far = 10000,
- },
- PotentialTargets = {
- "JUPITER", "IO", "EUROPA", "GANYMEDE", "CALLISTO"
- }
},
Transform = {
Translation = {
@@ -74,7 +76,7 @@ return {
Position = {0, -10000000, 0}
},
},
- },
+ },
-- CallistoTrail module
{
Name = "CallistoTrail",
@@ -93,7 +95,7 @@ return {
Type = "simple",
Color = "${COMMON_MODULE}/textures/glare_blue.png",
-- need to add different texture
- },
+ },
},
}
}
diff --git a/data/scene/newhorizons/jupiter/europa/europa.mod b/data/scene/newhorizons/jupiter/europa/europa.mod
index f09899f0f3..31933603e7 100644
--- a/data/scene/newhorizons/jupiter/europa/europa.mod
+++ b/data/scene/newhorizons/jupiter/europa/europa.mod
@@ -22,20 +22,22 @@ return {
Observer = "NEW HORIZONS",
Target = "EUROPA",
Aberration = "NONE",
- AspectRatio = 2
+ AspectRatio = 2,
+
+ Instrument = {
+ Name = "NH_LORRI",
+ Method = "ELLIPSOID",
+ Aberration = "NONE",
+ Fovy = 0.2907,
+ Aspect = 1,
+ Near = 0.2,
+ Far = 10000,
+ },
+
+ PotentialTargets = {
+ "JUPITER", "IO", "EUROPA", "GANYMEDE", "CALLISTO"
+ }
},
- Instrument = {
- Name = "NH_LORRI",
- Method = "ELLIPSOID",
- Aberration = "NONE",
- Fovy = 0.2907,
- Aspect = 1,
- Near = 0.2,
- Far = 10000,
- },
- PotentialTargets = {
- "JUPITER", "IO", "EUROPA", "GANYMEDE", "CALLISTO"
- }
},
Transform = {
Translation = {
diff --git a/data/scene/newhorizons/jupiter/ganymede/ganymede.mod b/data/scene/newhorizons/jupiter/ganymede/ganymede.mod
index eb6d0aa01b..0e7952fa87 100644
--- a/data/scene/newhorizons/jupiter/ganymede/ganymede.mod
+++ b/data/scene/newhorizons/jupiter/ganymede/ganymede.mod
@@ -22,20 +22,22 @@ return {
Observer = "NEW HORIZONS",
Target = "GANYMEDE",
Aberration = "NONE",
- AspectRatio = 2
+ AspectRatio = 2,
+
+ Instrument = {
+ Name = "NH_LORRI",
+ Method = "ELLIPSOID",
+ Aberration = "NONE",
+ Fovy = 0.2907,
+ Aspect = 1,
+ Near = 0.2,
+ Far = 10000,
+ },
+
+ PotentialTargets = {
+ "JUPITER", "IO", "EUROPA", "GANYMEDE", "CALLISTO"
+ }
},
- Instrument = {
- Name = "NH_LORRI",
- Method = "ELLIPSOID",
- Aberration = "NONE",
- Fovy = 0.2907,
- Aspect = 1,
- Near = 0.2,
- Far = 10000,
- },
- PotentialTargets = {
- "JUPITER", "IO", "EUROPA", "GANYMEDE", "CALLISTO"
- }
},
Transform = {
Translation = {
diff --git a/data/scene/newhorizons/jupiter/io/io.mod b/data/scene/newhorizons/jupiter/io/io.mod
index a5fe7540b3..e6b481c40c 100644
--- a/data/scene/newhorizons/jupiter/io/io.mod
+++ b/data/scene/newhorizons/jupiter/io/io.mod
@@ -22,20 +22,22 @@ return {
Observer = "NEW HORIZONS",
Target = "IO",
Aberration = "NONE",
- AspectRatio = 2
+ AspectRatio = 2,
+
+ Instrument = {
+ Name = "NH_LORRI",
+ Method = "ELLIPSOID",
+ Aberration = "NONE",
+ Fovy = 0.2907,
+ Aspect = 1,
+ Near = 0.2,
+ Far = 10000,
+ },
+
+ PotentialTargets = {
+ "JUPITER", "IO", "EUROPA", "GANYMEDE", "CALLISTO"
+ }
},
- Instrument = {
- Name = "NH_LORRI",
- Method = "ELLIPSOID",
- Aberration = "NONE",
- Fovy = 0.2907,
- Aspect = 1,
- Near = 0.2,
- Far = 10000,
- },
- PotentialTargets = {
- "JUPITER", "IO", "EUROPA", "GANYMEDE", "CALLISTO"
- }
},
Transform = {
Translation = {
diff --git a/data/scene/newhorizons/jupiter/jupiter/jupiter.mod b/data/scene/newhorizons/jupiter/jupiter/jupiter.mod
index 04d07a3a1e..317ac79798 100644
--- a/data/scene/newhorizons/jupiter/jupiter/jupiter.mod
+++ b/data/scene/newhorizons/jupiter/jupiter/jupiter.mod
@@ -38,53 +38,54 @@ return {
Observer = "NEW HORIZONS",
Target = "JUPITER",
Aberration = "NONE",
- AspectRatio = 2
- },
- DataInputTranslation = {
- Instrument = {
- LORRI = {
- DetectorType = "Camera",
- Spice = {"NH_LORRI"},
- },
- },
- Target ={
- Read = {
- "TARGET_NAME",
- "INSTRUMENT_HOST_NAME",
- "INSTRUMENT_ID",
- "START_TIME",
- "STOP_TIME",
- "DETECTOR_TYPE",
- --"SEQUENCE_ID",
- },
- Convert = {
- JRINGS = {"IMAGE-PLANE" },
- J1IO = {"IO" },
- J2EUROPA = {"EUROPA" },
- J6HIMALIA = {"IMAGE-PLANE" },
- J7ELARA = {"IMAGE-PLANE" },
- CALIBRATION = {"CALIBRATION" },
- JUPITER = {"JUPITER" },
- CALLISTO = {"CALLISTO" },
- GANYMEDE = {"GANYMEDE" },
- EARTH = {"EARTH" },
- NEWHORIZONS = {"NEW HORIZONS"},
- CCD = {"CAMERA" },
- FRAMECCD = {"SCANNER" },
+ AspectRatio = 2,
+
+ DataInputTranslation = {
+ Instrument = {
+ LORRI = {
+ DetectorType = "Camera",
+ Spice = {"NH_LORRI"},
+ },
+ },
+ Target ={
+ Read = {
+ "TARGET_NAME",
+ "INSTRUMENT_HOST_NAME",
+ "INSTRUMENT_ID",
+ "START_TIME",
+ "STOP_TIME",
+ "DETECTOR_TYPE",
+ --"SEQUENCE_ID",
+ },
+ Convert = {
+ JRINGS = {"IMAGE-PLANE" },
+ J1IO = {"IO" },
+ J2EUROPA = {"EUROPA" },
+ J6HIMALIA = {"IMAGE-PLANE" },
+ J7ELARA = {"IMAGE-PLANE" },
+ CALIBRATION = {"CALIBRATION" },
+ JUPITER = {"JUPITER" },
+ CALLISTO = {"CALLISTO" },
+ GANYMEDE = {"GANYMEDE" },
+ EARTH = {"EARTH" },
+ NEWHORIZONS = {"NEW HORIZONS"},
+ CCD = {"CAMERA" },
+ FRAMECCD = {"SCANNER" },
+ },
},
},
- },
- Instrument = {
- Name = "NH_LORRI",
- Method = "ELLIPSOID",
- Aberration = "NONE",
- Fovy = 0.2907,
- Aspect = 1,
- Near = 0.2,
- Far = 10000,
- },
- PotentialTargets = {
- "JUPITER", "IO", "EUROPA", "GANYMEDE", "CALLISTO"
+ Instrument = {
+ Name = "NH_LORRI",
+ Method = "ELLIPSOID",
+ Aberration = "NONE",
+ Fovy = 0.2907,
+ Aspect = 1,
+ Near = 0.2,
+ Far = 10000,
+ },
+ PotentialTargets = {
+ "JUPITER", "IO", "EUROPA", "GANYMEDE", "CALLISTO"
+ }
}
},
Transform = {
diff --git a/data/scene/newhorizons/newhorizons/newhorizons.mod b/data/scene/newhorizons/newhorizons/newhorizons.mod
index af08d5f56b..e9935d5906 100644
--- a/data/scene/newhorizons/newhorizons/newhorizons.mod
+++ b/data/scene/newhorizons/newhorizons/newhorizons.mod
@@ -90,7 +90,7 @@ return {
Geometry = {
Type = "MultiModelGeometry",
GeometryFile = "models/NewHorizonsCleanModel.obj",
- Magnification = 4,
+ -- Magnification = 4,
},
Textures = {
Type = "simple",
@@ -114,6 +114,10 @@ return {
SourceFrame = "NH_SPACECRAFT",
DestinationFrame = "GALACTIC",
},
+ Scale = {
+ Type = "StaticScale",
+ Scale = 1000
+ }
},
},
--NewHorizonsTrail module
@@ -150,7 +154,7 @@ return {
Geometry = {
Type = "MultiModelGeometry",
GeometryFile = "models/Labels.obj",
- Magnification = 4,
+ -- Magnification = 4,
},
Textures = {
Type = "simple",
@@ -166,7 +170,7 @@ return {
Fadeable = false,
Ghosting = false,
},
- },
+ }
},
{
diff --git a/data/scene/newhorizons/pluto/charon/charon.mod b/data/scene/newhorizons/pluto/charon/charon.mod
index d800cce9c9..01c370acc6 100644
--- a/data/scene/newhorizons/pluto/charon/charon.mod
+++ b/data/scene/newhorizons/pluto/charon/charon.mod
@@ -22,38 +22,35 @@ return {
Parent = "PlutoBarycenter",
Renderable = {
Type = "RenderablePlanetProjection",
- Frame = "IAU_CHARON",
- Body = "CHARON",
Geometry = {
Type = "SimpleSphere",
Radius = { 6.035 , 5 },
Segments = 100
},
Textures = {
- Type = "simple",
Color = ColorTexture,
Height = "textures/cpdem-Mcolor2-MLorriCA-lr-5_ZMfs-cyl.jpg",
- Project = "textures/defaultProj.png",
- Sequencing = "true",
},
Projection = {
Observer = "NEW HORIZONS",
Target = "CHARON",
Aberration = "NONE",
- AspectRatio = 2
- },
- Instrument = {
- Name = "NH_LORRI",
- Method = "ELLIPSOID",
- Aberration = "NONE",
- Fovy = 0.2907,
- Aspect = 1,
- Near = 0.2,
- Far = 10000,
- },
- PotentialTargets = {
- "PLUTO",
- "CHARON"
+ AspectRatio = 2,
+
+ Instrument = {
+ Name = "NH_LORRI",
+ Method = "ELLIPSOID",
+ Aberration = "NONE",
+ Fovy = 0.2907,
+ Aspect = 1,
+ Near = 0.2,
+ Far = 10000,
+ },
+
+ PotentialTargets = {
+ "PLUTO",
+ "CHARON"
+ }
}
},
Transform = {
diff --git a/data/scene/newhorizons/pluto/pluto/pluto.mod b/data/scene/newhorizons/pluto/pluto/pluto.mod
index e6c4537046..08eb750c1b 100644
--- a/data/scene/newhorizons/pluto/pluto/pluto.mod
+++ b/data/scene/newhorizons/pluto/pluto/pluto.mod
@@ -36,19 +36,14 @@ return {
Parent = "PlutoBarycenter",
Renderable = {
Type = "RenderablePlanetProjection",
- Frame = "IAU_PLUTO",
- Body = "PLUTO",
Geometry = {
Type = "SimpleSphere",
Radius = { 1.173 , 6 },
Segments = 100
},
Textures = {
- Type = "simple",
Color = ColorTexture,
Height = "textures/pluto_shenk_heightmap.jpg",
- Project = "textures/3.jpg",
- Sequencing = "true"
},
Projection = {
Sequence = "${OPENSPACE_DATA}/scene/newhorizons/pluto/pluto/images",
@@ -57,103 +52,106 @@ return {
Observer = "NEW HORIZONS",
Target = "PLUTO",
Aberration = "NONE",
- AspectRatio = 2
- },
- DataInputTranslation = {
- Instrument = {
- LORRI = {
- DetectorType = "Camera",
- Spice = {"NH_LORRI"},
- },
- RALPH_MVIC_PAN_FRAME = {
- DetectorType = "Scanner",
- StopCommand = "RALPH_ABORT",
- Spice = {"NH_RALPH_MVIC_FT"},
- },
- RALPH_MVIC_COLOR = {
- DetectorType = "Scanner",
- StopCommand = "END_NOM",
- Spice = { "NH_RALPH_MVIC_NIR",
- "NH_RALPH_MVIC_METHANE",
- "NH_RALPH_MVIC_RED",
- "NH_RALPH_MVIC_BLUE" },
- },
- RALPH_LEISA = {
- DetectorType = "Scanner",
- StopCommand = "END_NOM",
- Spice = {"NH_RALPH_LEISA"},
- },
- RALPH_MVIC_PAN1 = {
- DetectorType = "Scanner",
- StopCommand = "END_NOM",
- Spice = {"NH_RALPH_MVIC_PAN1"},
- },
- RALPH_MVIC_PAN2 = {
- DetectorType = "Scanner",
- StopCommand = "END_NOM",
- Spice = {"NH_RALPH_MVIC_PAN2"},
- },
- ALICE_Use_AIRGLOW = {
- DetectorType = "Scanner",
- StopCommand = "ALICE_END_PIXELLIST",
- Spice = {"NH_ALICE_AIRGLOW"},
- },
- ALICE_Use_AIRGLOW = {
- DetectorType = "Scanner",
- StopCommand = "ALICE_END_HISTOGRAM",
- Spice = {"NH_ALICE_AIRGLOW"},
- },
- ALICE_Use_SOCC = {
- DetectorType = "Scanner",
- StopCommand = "ALICE_END_PIXELLIST",
- Spice = {"NH_ALICE_SOC"},
- },
- ALICE_Use_SOCC = {
- DetectorType = "Scanner",
- StopCommand = "ALICE_END_HISTOGRAM",
- Spice = {"NH_ALICE_SOC"},
- },
- REX_START = {
- DetectorType = "Scanner",
- StopCommand = "REX_MODE_OFF",
- Spice = { "NH_REX" },
- }
- },
- Target ={
- Read = {
- "TARGET_NAME",
- "INSTRUMENT_HOST_NAME",
- "INSTRUMENT_ID",
- "START_TIME",
- "STOP_TIME",
- "DETECTOR_TYPE",
- --"SEQUENCE_ID",
- },
- Convert = {
- PLUTO = {"PLUTO" },
- NEWHORIZONS = {"NEW HORIZONS"},
- CCD = {"CAMERA" },
- FRAMECCD = {"SCANNER" },
+ AspectRatio = 2,
+
+ DataInputTranslation = {
+ Instrument = {
+ LORRI = {
+ DetectorType = "Camera",
+ Spice = {"NH_LORRI"},
+ },
+ RALPH_MVIC_PAN_FRAME = {
+ DetectorType = "Scanner",
+ StopCommand = "RALPH_ABORT",
+ Spice = {"NH_RALPH_MVIC_FT"},
+ },
+ RALPH_MVIC_COLOR = {
+ DetectorType = "Scanner",
+ StopCommand = "END_NOM",
+ Spice = { "NH_RALPH_MVIC_NIR",
+ "NH_RALPH_MVIC_METHANE",
+ "NH_RALPH_MVIC_RED",
+ "NH_RALPH_MVIC_BLUE" },
+ },
+ RALPH_LEISA = {
+ DetectorType = "Scanner",
+ StopCommand = "END_NOM",
+ Spice = {"NH_RALPH_LEISA"},
+ },
+ RALPH_MVIC_PAN1 = {
+ DetectorType = "Scanner",
+ StopCommand = "END_NOM",
+ Spice = {"NH_RALPH_MVIC_PAN1"},
+ },
+ RALPH_MVIC_PAN2 = {
+ DetectorType = "Scanner",
+ StopCommand = "END_NOM",
+ Spice = {"NH_RALPH_MVIC_PAN2"},
+ },
+ ALICE_Use_AIRGLOW = {
+ DetectorType = "Scanner",
+ StopCommand = "ALICE_END_PIXELLIST",
+ Spice = {"NH_ALICE_AIRGLOW"},
+ },
+ ALICE_Use_AIRGLOW = {
+ DetectorType = "Scanner",
+ StopCommand = "ALICE_END_HISTOGRAM",
+ Spice = {"NH_ALICE_AIRGLOW"},
+ },
+ ALICE_Use_SOCC = {
+ DetectorType = "Scanner",
+ StopCommand = "ALICE_END_PIXELLIST",
+ Spice = {"NH_ALICE_SOC"},
+ },
+ ALICE_Use_SOCC = {
+ DetectorType = "Scanner",
+ StopCommand = "ALICE_END_HISTOGRAM",
+ Spice = {"NH_ALICE_SOC"},
+ },
+ REX_START = {
+ DetectorType = "Scanner",
+ StopCommand = "REX_MODE_OFF",
+ Spice = { "NH_REX" },
+ }
+ },
+ Target ={
+ Read = {
+ "TARGET_NAME",
+ "INSTRUMENT_HOST_NAME",
+ "INSTRUMENT_ID",
+ "START_TIME",
+ "STOP_TIME",
+ "DETECTOR_TYPE",
+ --"SEQUENCE_ID",
+ },
+ Convert = {
+ PLUTO = {"PLUTO" },
+ NEWHORIZONS = {"NEW HORIZONS"},
+ CCD = {"CAMERA" },
+ FRAMECCD = {"SCANNER" },
+ },
},
},
+
+ Instrument = {
+ Name = "NH_LORRI",
+ Method = "ELLIPSOID",
+ Aberration = "NONE",
+ Fovy = 0.2907,
+ Aspect = 1,
+ Near = 0.2,
+ Far = 10000,
+ },
+
+ PotentialTargets = {
+ "PLUTO",
+ "CHARON",
+ "NIX",
+ "HYDRA",
+ "P5",
+ "P4",
+ }
},
- Instrument = {
- Name = "NH_LORRI",
- Method = "ELLIPSOID",
- Aberration = "NONE",
- Fovy = 0.2907,
- Aspect = 1,
- Near = 0.2,
- Far = 10000,
- },
- PotentialTargets = {
- "PLUTO",
- "CHARON",
- "NIX",
- "HYDRA",
- "P5",
- "P4",
- }
},
Transform = {
Translation = {
diff --git a/data/scene/osirisrex/bennu/bennu.mod b/data/scene/osirisrex/bennu/bennu.mod
index eeabed0e09..cbbfc05ad3 100644
--- a/data/scene/osirisrex/bennu/bennu.mod
+++ b/data/scene/osirisrex/bennu/bennu.mod
@@ -38,53 +38,51 @@ return {
Project = "textures/defaultProj.png",
Default = "textures/defaultProj.png"
},
- Rotation = {
- Source = "IAU_BENNU",
- Destination = "GALACTIC"
- },
Projection = {
Sequence = "InstrumentTimes",
SequenceType = "instrument-times",
Observer = "OSIRIS-REX",
Target = BENNU_BODY,
Aberration = "NONE",
- AspectRatio = 2
- },
- DataInputTranslation = {
- Instruments = {
- ORX_OCAMS_POLYCAM = {
- DetectorType = "Camera",
- Spice = {"ORX_OCAMS_POLYCAM"},
- Files = {
- "BaseballDiamond_PolyCam.txt",
- --"OrbitalB_Site08_PolyCamImages.txt",
- "Recon_225m_Equatorial_PolyCam.txt",
+ AspectRatio = 2,
+
+ DataInputTranslation = {
+ Instruments = {
+ ORX_OCAMS_POLYCAM = {
+ DetectorType = "Camera",
+ Spice = {"ORX_OCAMS_POLYCAM"},
+ Files = {
+ "BaseballDiamond_PolyCam.txt",
+ --"OrbitalB_Site08_PolyCamImages.txt",
+ "Recon_225m_Equatorial_PolyCam.txt",
+ },
},
- },
- ORX_REXIS = {
- DetectorType = "Camera",
- Spice = {"ORX_REXIS"},
- Files = {
- "DetailedSurvey_EquatorialStations_Spectrometers.txt",
- "Recon_225m_Equatorial_spectrometers.txt",
- "Recon_525m_Equatorial_spectrometers.txt",
+ ORX_REXIS = {
+ DetectorType = "Camera",
+ Spice = {"ORX_REXIS"},
+ Files = {
+ "DetailedSurvey_EquatorialStations_Spectrometers.txt",
+ "Recon_225m_Equatorial_spectrometers.txt",
+ "Recon_525m_Equatorial_spectrometers.txt",
+ },
},
+ },
+ Target = {
+ Body = BENNU_BODY, -- Do we need this?
},
- },
- Target = {
- Body = BENNU_BODY, -- Do we need this?
+ },
+
+ Instrument = { -- INVALID DATA - JUST FOR TESTING
+ Name = "ORX_OCAMS_POLYCAM",
+ Method = "ELLIPSOID",
+ Aberration = "NONE",
+ Fovy = 0.792,
+ Aspect = 1,
+ Near = 0.01,
+ Far = 1000000,
},
},
- Instrument = { -- INVALID DATA - JUST FOR TESTING
- Name = "ORX_OCAMS_POLYCAM",
- Method = "ELLIPSOID",
- Aberration = "NONE",
- Fovy = 0.792,
- Aspect = 1,
- Near = 0.01,
- Far = 1000000,
- },
},
Transform = {
diff --git a/data/scene/osirisrex/osirisrex/osirisrex.mod b/data/scene/osirisrex/osirisrex/osirisrex.mod
index 51272879be..d8dded5250 100644
--- a/data/scene/osirisrex/osirisrex/osirisrex.mod
+++ b/data/scene/osirisrex/osirisrex/osirisrex.mod
@@ -137,6 +137,9 @@ return {
},
PotentialTargets = {
BENNU_BODY -- Bennu
+ },
+ FrameConversions = {
+ [BENNU_BODY] = "IAU_BENNU"
}
},
},
diff --git a/data/scene/rosetta/67P/67P.mod b/data/scene/rosetta/67P/67P.mod
index 1b8d3a5aa7..5358b6b9ce 100644
--- a/data/scene/rosetta/67P/67P.mod
+++ b/data/scene/rosetta/67P/67P.mod
@@ -17,22 +17,14 @@ return {
Renderable = {
Type = "RenderableModelProjection",
- Body = "CHURYUMOV-GERASIMENKO",
Geometry = {
Type = "MultiModelGeometry",
GeometryFile = "obj/67P_rotated_5_130.obj",
Magnification = 0,
},
Textures = {
- Type = "simple",
Color = "textures/gray.jpg",
-- Color = "textures/may9_map.jpg",
- Project = "textures/defaultProj.png",
- Default = "textures/defaultProj.png"
- },
- Rotation = {
- Source = "67P/C-G_CK",
- Destination = "GALACTIC"
},
Projection = {
Sequence = "rosettaimages",
@@ -41,43 +33,45 @@ return {
Target = "CHURYUMOV-GERASIMENKO",
Aberration = "NONE",
TextureMap = true,
- ShadowMap = true
- },
- DataInputTranslation = {
+ ShadowMap = true,
+
+ DataInputTranslation = {
+ Instrument = {
+ NAVCAM = {
+ DetectorType = "Camera",
+ Spice = {"ROS_NAVCAM-A"},
+ },
+ },
+ Target = {
+ Read = {
+ "TARGET_NAME",
+ "INSTRUMENT_HOST_NAME",
+ "INSTRUMENT_ID",
+ "START_TIME",
+ "STOP_TIME",
+ },
+ Convert = {
+ CHURYUMOV = {"CHURYUMOV-GERASIMENKO"},
+ ROSETTA = {"ROSETTA" },
+ --NAVCAM = {"NAVCAM"},
+ ["ROSETTA-ORBITER"] = {"ROSETTA" },
+ CHURYUMOVGERASIMENKO11969R1 = {"CHURYUMOV-GERASIMENKO"},
+ CHURYUMOVGERASIMENKO = {"CHURYUMOV-GERASIMENKO"},
+ ["CHURYUMOV-GERASIMENKO1(1969R1)"] = {"CHURYUMOV-GERASIMENKO"},
+ --NAVIGATIONCAMERA = {"NAVCAM" },
+ },
+ },
+ },
+
Instrument = {
- NAVCAM = {
- DetectorType = "Camera",
- Spice = {"ROS_NAVCAM-A"},
- },
- },
- Target = {
- Read = {
- "TARGET_NAME",
- "INSTRUMENT_HOST_NAME",
- "INSTRUMENT_ID",
- "START_TIME",
- "STOP_TIME",
- },
- Convert = {
- CHURYUMOV = {"CHURYUMOV-GERASIMENKO"},
- ROSETTA = {"ROSETTA" },
- --NAVCAM = {"NAVCAM"},
- ["ROSETTA-ORBITER"] = {"ROSETTA" },
- CHURYUMOVGERASIMENKO11969R1 = {"CHURYUMOV-GERASIMENKO"},
- CHURYUMOVGERASIMENKO = {"CHURYUMOV-GERASIMENKO"},
- ["CHURYUMOV-GERASIMENKO1(1969R1)"] = {"CHURYUMOV-GERASIMENKO"},
- --NAVIGATIONCAMERA = {"NAVCAM" },
- },
+ Name = "ROS_NAVCAM-A",
+ Method = "ELLIPSOID",
+ Aberration = "NONE",
+ Fovy = 5.00,
+ Aspect = 1
},
},
- Instrument = {
- Name = "ROS_NAVCAM-A",
- Method = "ELLIPSOID",
- Aberration = "NONE",
- Fovy = 5.00,
- Aspect = 1
- },
BoundingSphereRadius = 5000.0
},
Transform = {
diff --git a/data/scene/rosetta/rosetta/rosetta.mod b/data/scene/rosetta/rosetta/rosetta.mod
index 1bb96fe198..dffee7acb6 100644
--- a/data/scene/rosetta/rosetta/rosetta.mod
+++ b/data/scene/rosetta/rosetta/rosetta.mod
@@ -437,6 +437,9 @@ return {
},
PotentialTargets = {
"CHURYUMOV-GERASIMENKO"
+ },
+ FrameConversions = {
+ ["CHURYUMOV-GERASIMENKO"] = "67P/C-G_CK"
}
},
},
diff --git a/modules/base/basemodule.cpp b/modules/base/basemodule.cpp
index f52e3acd0f..bc9ddc22e9 100644
--- a/modules/base/basemodule.cpp
+++ b/modules/base/basemodule.cpp
@@ -139,7 +139,9 @@ std::vector BaseModule::documentations() const {
SpiceRotation::Documentation(),
StaticScale::Documentation(),
StaticTranslation::Documentation(),
- SpiceTranslation::Documentation()
+ SpiceTranslation::Documentation(),
+ modelgeometry::ModelGeometry::Documentation(),
+ planetgeometry::PlanetGeometry::Documentation()
};
}
diff --git a/modules/base/rendering/modelgeometry.cpp b/modules/base/rendering/modelgeometry.cpp
index 655c883a2e..38288d425e 100644
--- a/modules/base/rendering/modelgeometry.cpp
+++ b/modules/base/rendering/modelgeometry.cpp
@@ -23,6 +23,8 @@
****************************************************************************************/
#include
+
+#include
#include
#include
#include
@@ -35,59 +37,70 @@ namespace {
const int8_t CurrentCacheVersion = 3;
const std::string keyType = "Type";
const std::string keyName = "Name";
- const std::string keySize = "Magnification";
}
namespace openspace {
namespace modelgeometry {
+Documentation ModelGeometry::Documentation() {
+ using namespace documentation;
+ return {
+ "Model Geometry",
+ "base_geometry_model",
+ {
+ {
+ keyType,
+ new StringVerifier,
+ "The type of the Model Geometry that should be generated",
+ Optional::No
+ },
+ {
+ keyGeomModelFile,
+ new StringVerifier,
+ "The file that should be loaded in this ModelGeometry. The file can "
+ "contain filesystem tokens or can be specified relatively to the "
+ "location of the .mod file.",
+ Optional::No
+ }
+ }
+ };
+}
+
+
ModelGeometry* ModelGeometry::createFromDictionary(const ghoul::Dictionary& dictionary) {
- std::string geometryType;
- const bool success = dictionary.getValue(
- keyType, geometryType);
- if (!success) {
- LERROR("ModelGeometry did not contain a correct value of the key '"
- << keyType << "'");
- return nullptr;
+ if (!dictionary.hasKeyAndValue(keyType)) {
+ throw ghoul::RuntimeError("Dictionary did not contain a key 'Type'");
}
- ghoul::TemplateFactory* factory
- = FactoryManager::ref().factory();
+
+ std::string geometryType = dictionary.value(keyType);
+ auto factory = FactoryManager::ref().factory();
ModelGeometry* result = factory->create(geometryType, dictionary);
if (result == nullptr) {
- LERROR("Failed to create a ModelGeometry object of type '" << geometryType
- << "'");
- return nullptr;
+ throw ghoul::RuntimeError(
+ "Failed to create a ModelGeometry object of type '" + geometryType + "'"
+ );
}
return result;
}
ModelGeometry::ModelGeometry(const ghoul::Dictionary& dictionary)
: _parent(nullptr)
- , _magnification("magnification", "Magnification", 1.f, 0.f, 10.f)
, _mode(GL_TRIANGLES)
{
+ documentation::testSpecificationAndThrow(
+ Documentation(),
+ dictionary,
+ "ModelGeometry"
+ );
+
setName("ModelGeometry");
std::string name;
bool success = dictionary.getValue(keyName, name);
ghoul_assert(success, "Name tag was not present");
- if (dictionary.hasKeyAndValue(keySize))
- _magnification = static_cast(dictionary.value(keySize));
-
- success = dictionary.getValue(keyGeomModelFile, _file);
- if (!success) {
- LERROR("Geometric Model file of '" << name << "' did not provide a key '"
- << keyGeomModelFile << "'");
- }
- _file = FileSys.absolutePath(_file);
-
- if (!FileSys.fileExists(_file, ghoul::filesystem::FileSystem::RawPath::Yes))
- LERROR("Could not load the geometric model file '" << _file << "': File not found");
-
-
- addProperty(_magnification);
+ _file = absPath(dictionary.value(keyGeomModelFile));
}
double ModelGeometry::boundingRadius() const {
@@ -273,7 +286,6 @@ bool ModelGeometry::getIndices(std::vector* indexList) {
}
void ModelGeometry::setUniforms(ghoul::opengl::ProgramObject& program) {
- program.setUniform("_magnification", _magnification);
}
} // namespace modelgeometry
diff --git a/modules/base/rendering/modelgeometry.h b/modules/base/rendering/modelgeometry.h
index b85062b897..edfbada197 100644
--- a/modules/base/rendering/modelgeometry.h
+++ b/modules/base/rendering/modelgeometry.h
@@ -27,6 +27,7 @@
#include
+#include
#include
#include
#include
@@ -59,13 +60,14 @@ public:
virtual void setUniforms(ghoul::opengl::ProgramObject& program);
+ static openspace::Documentation Documentation();
+
protected:
Renderable* _parent;
bool loadObj(const std::string& filename);
bool loadCachedFile(const std::string& filename);
bool saveCachedFile(const std::string& filename);
- properties::FloatProperty _magnification;
GLuint _vaoID;
GLuint _vbo;
diff --git a/modules/base/rendering/planetgeometry.cpp b/modules/base/rendering/planetgeometry.cpp
index 32e366b0fd..a876bbf041 100644
--- a/modules/base/rendering/planetgeometry.cpp
+++ b/modules/base/rendering/planetgeometry.cpp
@@ -25,6 +25,8 @@
#include
#include
+#include
+
namespace {
const std::string _loggerCat = "PlanetGeometry";
const std::string KeyType = "Type";
@@ -33,22 +35,38 @@ namespace {
namespace openspace {
namespace planetgeometry {
-PlanetGeometry* PlanetGeometry::createFromDictionary(const ghoul::Dictionary& dictionary) {
- std::string geometryType;
- const bool success = dictionary.getValue(KeyType, geometryType);
- if (!success) {
- LERROR("PlanetGeometry did not contain a correct value of the key '"
- << KeyType << "'");
- return nullptr;
- }
- ghoul::TemplateFactory* factory
- = FactoryManager::ref().factory();
+Documentation PlanetGeometry::Documentation() {
+ using namespace documentation;
+ return {
+ "Planet Geometry",
+ "base_geometry_planet",
+ {
+ {
+ KeyType,
+ new StringVerifier,
+ "The type of the PlanetGeometry that will can be constructed.",
+ Optional::No
+ }
+ }
+ };
+}
+
+PlanetGeometry* PlanetGeometry::createFromDictionary(const ghoul::Dictionary& dictionary)
+{
+ documentation::testSpecificationAndThrow(
+ Documentation(),
+ dictionary,
+ "PlanetGeometry"
+ );
+
+ std::string geometryType = dictionary.value(KeyType);
+ auto factory = FactoryManager::ref().factory();
PlanetGeometry* result = factory->create(geometryType, dictionary);
if (result == nullptr) {
- LERROR("Failed to create a PlanetGeometry object of type '" << geometryType
- << "'");
- return nullptr;
+ throw ghoul::RuntimeError(
+ "Failed to create a PlanetGeometry object of type '" + geometryType + "'"
+ );
}
return result;
}
diff --git a/modules/base/rendering/planetgeometry.h b/modules/base/rendering/planetgeometry.h
index 3a38f3be81..2442fa11d5 100644
--- a/modules/base/rendering/planetgeometry.h
+++ b/modules/base/rendering/planetgeometry.h
@@ -26,10 +26,11 @@
#define __PLANETGEOMETRY_H__
#include
-#include
-#include
+
+#include
namespace openspace {
+class Renderable;
namespace planetgeometry {
@@ -43,6 +44,8 @@ public:
virtual void deinitialize();
virtual void render() = 0;
+ static openspace::Documentation Documentation();
+
protected:
Renderable* _parent;
};
diff --git a/modules/newhorizons/newhorizonsmodule.cpp b/modules/newhorizons/newhorizonsmodule.cpp
index 72caa9b844..49e3beb07e 100644
--- a/modules/newhorizons/newhorizonsmodule.cpp
+++ b/modules/newhorizons/newhorizonsmodule.cpp
@@ -71,4 +71,12 @@ void NewHorizonsModule::internalInitialize() {
fDecoder->registerClass("Target");
}
+std::vector NewHorizonsModule::documentations() const {
+ return {
+ RenderableModelProjection::Documentation(),
+ RenderablePlanetProjection::Documentation(),
+ ProjectionComponent::Documentation()
+ };
+}
+
} // namespace openspace
diff --git a/modules/newhorizons/newhorizonsmodule.h b/modules/newhorizons/newhorizonsmodule.h
index e4b57eaa7a..8bd39cbce4 100644
--- a/modules/newhorizons/newhorizonsmodule.h
+++ b/modules/newhorizons/newhorizonsmodule.h
@@ -33,6 +33,8 @@ class NewHorizonsModule : public OpenSpaceModule {
public:
NewHorizonsModule();
+ std::vector documentations() const override;
+
protected:
void internalInitialize() override;
};
diff --git a/modules/newhorizons/rendering/renderablefov.cpp b/modules/newhorizons/rendering/renderablefov.cpp
index 878d833186..aa29f631cb 100644
--- a/modules/newhorizons/rendering/renderablefov.cpp
+++ b/modules/newhorizons/rendering/renderablefov.cpp
@@ -46,6 +46,7 @@ namespace {
const std::string keyInstrumentMethod = "Instrument.Method";
const std::string keyInstrumentAberration = "Instrument.Aberration";
const std::string keyPotentialTargets = "PotentialTargets";
+ const std::string keyFrameConversions = "FrameConversions";
const int InterpolationSteps = 10;
const int Stride = 8;
@@ -94,6 +95,17 @@ RenderableFov::RenderableFov(const ghoul::Dictionary& dictionary)
_potentialTargets[i] = target;
}
+ ghoul::Dictionary frameConversions;
+ success = dictionary.getValue(keyFrameConversions, frameConversions);
+ if (success) {
+ for (const std::string& key : frameConversions.keys()) {
+ openspace::SpiceManager::ref().addFrame(
+ key,
+ frameConversions.value(key)
+ );
+ }
+ }
+
addProperty(_lineWidth);
addProperty(_drawSolid);
}
diff --git a/modules/newhorizons/rendering/renderablemodelprojection.cpp b/modules/newhorizons/rendering/renderablemodelprojection.cpp
index 3daadde566..76dc7dd40a 100644
--- a/modules/newhorizons/rendering/renderablemodelprojection.cpp
+++ b/modules/newhorizons/rendering/renderablemodelprojection.cpp
@@ -24,6 +24,7 @@
#include
+#include
#include
#include
#include
@@ -38,17 +39,62 @@ namespace {
const std::string _loggerCat = "RenderableModelProjection";
const std::string keySource = "Rotation.Source";
const std::string keyDestination = "Rotation.Destination";
- const std::string keyBody = "Body";
const std::string keyGeometry = "Geometry";
+ const std::string keyProjection = "Projection";
const std::string keyBoundingSphereRadius = "BoundingSphereRadius";
const std::string keyTextureColor = "Textures.Color";
- const std::string keyTextureProject = "Textures.Project";
- const std::string keyTextureDefault = "Textures.Default";
+
+ const std::string _destination = "GALACTIC";
}
namespace openspace {
+Documentation RenderableModelProjection::Documentation() {
+ using namespace documentation;
+
+ return {
+ "Renderable Model Projection",
+ "newhorizons_renderable_modelprojection",
+ {
+ {
+ "Type",
+ new StringEqualVerifier("RenderableModelProjection"),
+ "",
+ Optional::No
+ },
+ {
+ keyGeometry,
+ new ReferencingVerifier("base_geometry_model"),
+ "The geometry that is used for rendering this model.",
+ Optional::No
+ },
+ {
+ keyProjection,
+ new ReferencingVerifier("newhorizons_projectioncomponent"),
+ "Contains information about projecting onto this planet.",
+ Optional::No
+ },
+ {
+ keyTextureColor,
+ new StringVerifier,
+ "The base texture for the model that is shown before any projection "
+ "occurred.",
+ Optional::No
+ },
+ {
+ keyBoundingSphereRadius,
+ new DoubleVerifier,
+ "The radius of the bounding sphere of this object. This has to be a "
+ "radius that is larger than anything that is rendered by it. It has to "
+ "be at least as big as the convex hull of the object. The default value "
+ "is 10e9 meters.",
+ Optional::Yes
+ }
+ }
+ };
+}
+
RenderableModelProjection::RenderableModelProjection(const ghoul::Dictionary& dictionary)
: Renderable(dictionary)
, _colorTexturePath("colorTexture", "Color Texture")
@@ -59,44 +105,35 @@ RenderableModelProjection::RenderableModelProjection(const ghoul::Dictionary& di
, _geometry(nullptr)
, _performShading("performShading", "Perform Shading", true)
{
+ documentation::testSpecificationAndThrow(
+ Documentation(),
+ dictionary,
+ "RenderableModelProjection"
+ );
+
std::string name;
bool success = dictionary.getValue(SceneGraphNode::KeyName, name);
ghoul_assert(success, "Name was not passed to RenderableModelProjection");
- ghoul::Dictionary geometryDictionary;
- success = dictionary.getValue(keyGeometry, geometryDictionary);
- if (success) {
- using modelgeometry::ModelGeometry;
- geometryDictionary.setValue(SceneGraphNode::KeyName, name);
- _geometry = std::unique_ptr(
- ModelGeometry::createFromDictionary(geometryDictionary)
- );
- }
+ using ghoul::Dictionary;
+ Dictionary geometryDictionary = dictionary.value(keyGeometry);
+ using modelgeometry::ModelGeometry;
+ geometryDictionary.setValue(SceneGraphNode::KeyName, name);
+ _geometry = std::unique_ptr(
+ ModelGeometry::createFromDictionary(geometryDictionary)
+ );
- std::string texturePath = "";
- success = dictionary.getValue(keyTextureColor, texturePath);
- if (success)
- _colorTexturePath = absPath(texturePath);
+ _colorTexturePath = absPath(dictionary.value(keyTextureColor));
- success = dictionary.getValue(keyTextureDefault, texturePath);
- if (success)
- _defaultProjImage = absPath(texturePath);
-
addPropertySubOwner(_geometry.get());
addPropertySubOwner(_projectionComponent);
addProperty(_colorTexturePath);
_colorTexturePath.onChange(std::bind(&RenderableModelProjection::loadTextures, this));
- dictionary.getValue(keySource, _source);
- dictionary.getValue(keyDestination, _destination);
- dictionary.getValue(keyBody, _target);
-
-
- bool completeSuccess = true;
- completeSuccess &= _projectionComponent.initializeProjectionSettings(dictionary);
-
- openspace::SpiceManager::ref().addFrame(_target, _source);
+ _projectionComponent.initialize(
+ dictionary.value(keyProjection)
+ );
float boundingSphereRadius = 1.0e9;
dictionary.getValue(keyBoundingSphereRadius, boundingSphereRadius);
@@ -104,9 +141,6 @@ RenderableModelProjection::RenderableModelProjection(const ghoul::Dictionary& di
Renderable::addProperty(_performShading);
Renderable::addProperty(_rotation);
-
- success = _projectionComponent.initializeParser(dictionary);
- ghoul_assert(success, "");
}
bool RenderableModelProjection::isReady() const {
@@ -139,15 +173,12 @@ bool RenderableModelProjection::initialize() {
completeSuccess &= loadTextures();
- completeSuccess &= _projectionComponent.initialize();
+ completeSuccess &= _projectionComponent.initializeGL();
auto bs = getBoundingSphere();
completeSuccess &= _geometry->initialize(this);
setBoundingSphere(bs); // ignore bounding sphere set by geometry.
- completeSuccess &= !_source.empty();
- completeSuccess &= !_destination.empty();
-
return completeSuccess;
}
@@ -246,18 +277,12 @@ void RenderableModelProjection::update(const UpdateData& data) {
}
}
- // set spice-orientation in accordance to timestamp
- if (!_source.empty()) {
- _stateMatrix = SpiceManager::ref().positionTransformMatrix(
- _source, _destination, _time
- );
- }
-
- double lt;
+ _stateMatrix = data.modelTransform.rotation;
+
glm::dvec3 p =
- openspace::SpiceManager::ref().targetPosition(
- "SUN", _target, "GALACTIC", {}, _time, lt
- );
+ OsEng.renderEngine().scene()->sceneGraphNode("Sun")->worldPosition() -
+ data.modelTransform.translation;
+
_sunPosition = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z);
}
@@ -308,7 +333,6 @@ void RenderableModelProjection::imageProjectGPU(
void RenderableModelProjection::attitudeParameters(double time) {
try {
- _stateMatrix = SpiceManager::ref().positionTransformMatrix(_source, _destination, time);
_instrumentMatrix = SpiceManager::ref().positionTransformMatrix(_projectionComponent.instrumentId(), _destination, time);
}
catch (const SpiceManager::SpiceException& e) {
diff --git a/modules/newhorizons/rendering/renderablemodelprojection.h b/modules/newhorizons/rendering/renderablemodelprojection.h
index 1a0ef2c259..60349f5033 100644
--- a/modules/newhorizons/rendering/renderablemodelprojection.h
+++ b/modules/newhorizons/rendering/renderablemodelprojection.h
@@ -28,6 +28,7 @@
#include
#include
+#include
#include
#include
@@ -59,6 +60,8 @@ public:
ghoul::opengl::Texture& baseTexture() const;
+ static openspace::Documentation Documentation();
+
private:
bool loadTextures();
void attitudeParameters(double time);
@@ -83,11 +86,6 @@ private:
glm::dmat3 _stateMatrix;
glm::dmat3 _instrumentMatrix;
- std::string _defaultProjImage;
- std::string _source;
- std::string _destination;
- std::string _target;
-
// uniforms
glm::vec2 _camScaling;
glm::vec3 _up;
diff --git a/modules/newhorizons/rendering/renderableplanetprojection.cpp b/modules/newhorizons/rendering/renderableplanetprojection.cpp
index 3f892aecb0..80338f7e79 100644
--- a/modules/newhorizons/rendering/renderableplanetprojection.cpp
+++ b/modules/newhorizons/rendering/renderableplanetprojection.cpp
@@ -26,6 +26,7 @@
#include
+#include
#include
#include
#include
@@ -45,16 +46,64 @@
namespace {
const std::string _loggerCat = "RenderablePlanetProjection";
- const std::string keyFrame = "Frame";
const std::string keyGeometry = "Geometry";
+ const std::string keyProjection = "Projection";
+ const std::string keyColorTexture = "Textures.Color";
+ const std::string keyHeightTexture = "Textures.Height";
+
+
const std::string keyRadius = "Geometry.Radius";
const std::string keyShading = "PerformShading";
- const std::string keyBody = "Body";
const std::string _mainFrame = "GALACTIC";
}
namespace openspace {
+Documentation RenderablePlanetProjection::Documentation() {
+ using namespace openspace::documentation;
+ return {
+ "Renderable Planet Projection",
+ "newhorizons_renderable_planetprojection",
+ {
+ {
+ "Type",
+ new StringEqualVerifier("RenderablePlanetProjection"),
+ "",
+ Optional::No
+ },
+ {
+ keyGeometry,
+ new ReferencingVerifier("base_geometry_planet"),
+ "The geometry that is used for rendering this planet.",
+ Optional::No
+ },
+ {
+ keyProjection,
+ new ReferencingVerifier("newhorizons_projectioncomponent"),
+ "Contains information about projecting onto this planet.",
+ Optional::No
+ },
+ {
+ keyColorTexture,
+ new StringVerifier,
+ "The path to the base color texture that is used on the planet prior to "
+ "any image projection. The path can use tokens of the form '${...}' or "
+ "be specified relative to the directory of the mod file.",
+ Optional::No
+ },
+ {
+ keyHeightTexture,
+ new StringVerifier,
+ "The path to the height map texture that is used on the planet. The path "
+ "can use tokens of the form '${...}' or be specified relative to the "
+ "directory of the mod file. If no height map is specified the planet "
+ "does not use a height field.",
+ Optional::Yes
+ }
+ }
+ };
+}
+
RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary& dictionary)
: Renderable(dictionary)
, _colorTexturePath("planetTexture", "RGB Texture")
@@ -68,6 +117,12 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary&
, _heightMapTexture(nullptr)
, _capture(false)
{
+ documentation::testSpecificationAndThrow(
+ Documentation(),
+ dictionary,
+ "RenderablePlanetProject"
+ );
+
std::string name;
bool success = dictionary.getValue(SceneGraphNode::KeyName, name);
ghoul_assert(success, "");
@@ -83,11 +138,7 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary&
);
}
- dictionary.getValue(keyFrame, _frame);
- dictionary.getValue(keyBody, _body);
-
- success = _projectionComponent.initializeProjectionSettings(dictionary);
- ghoul_assert(success, "");
+ _projectionComponent.initialize(dictionary.value(keyProjection));
// TODO: textures need to be replaced by a good system similar to the geometry as soon
// as the requirements are fixed (ab)
@@ -117,9 +168,6 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary&
addProperty(_heightExaggeration);
addProperty(_debugProjectionTextureRotation);
-
- success = _projectionComponent.initializeParser(dictionary);
- ghoul_assert(success, "");
}
RenderablePlanetProjection::~RenderablePlanetProjection() {}
@@ -138,7 +186,7 @@ bool RenderablePlanetProjection::initialize() {
);
completeSuccess &= loadTextures();
- completeSuccess &= _projectionComponent.initialize();
+ completeSuccess &= _projectionComponent.initializeGL();
completeSuccess &= _geometry->initialize(this);
if (completeSuccess) {
@@ -233,7 +281,6 @@ void RenderablePlanetProjection::imageProjectGPU(
void RenderablePlanetProjection::attitudeParameters(double time) {
// precomputations for shader
- _stateMatrix = SpiceManager::ref().positionTransformMatrix(_frame, _mainFrame, time);
_instrumentMatrix = SpiceManager::ref().positionTransformMatrix(
_projectionComponent.instrumentId(), _mainFrame, time
);
@@ -256,12 +303,7 @@ void RenderablePlanetProjection::attitudeParameters(double time) {
glm::vec3(0, 1, 0)
);
- for (int i = 0; i < 3; i++){
- for (int j = 0; j < 3; j++){
- _transform[i][j] = static_cast(_stateMatrix[i][j]);
- }
- }
- _transform = _transform * rot * roty * rotProp;
+ _transform = glm::mat4(_stateMatrix) * rot * roty * rotProp;
glm::dvec3 bs;
try {
@@ -411,6 +453,7 @@ void RenderablePlanetProjection::update(const UpdateData& data) {
}
}
+ _stateMatrix = data.modelTransform.rotation;
}
bool RenderablePlanetProjection::loadTextures() {
diff --git a/modules/newhorizons/rendering/renderableplanetprojection.h b/modules/newhorizons/rendering/renderableplanetprojection.h
index c5f2553183..6e7cac4630 100644
--- a/modules/newhorizons/rendering/renderableplanetprojection.h
+++ b/modules/newhorizons/rendering/renderableplanetprojection.h
@@ -26,10 +26,11 @@
#define __RENDERABLEPLANETPROJECTION_H__
#include
-#include
#include
+#include
+#include
#include
#include
#include
@@ -56,6 +57,8 @@ public:
void update(const UpdateData& data) override;
ghoul::opengl::Texture& baseTexture() const;
+ static openspace::Documentation Documentation();
+
protected:
bool loadTextures();
void attitudeParameters(double time);
@@ -95,7 +98,6 @@ private:
std::vector _imageTimes;
- std::string _body;
std::string _frame;
bool _capture;
diff --git a/modules/newhorizons/util/projectioncomponent.cpp b/modules/newhorizons/util/projectioncomponent.cpp
index 21a36cbd61..9ff4439010 100644
--- a/modules/newhorizons/util/projectioncomponent.cpp
+++ b/modules/newhorizons/util/projectioncomponent.cpp
@@ -29,6 +29,7 @@
#include
#include
+#include
#include
#include
@@ -44,17 +45,18 @@ namespace {
const std::string keyInstrumentFovy = "Instrument.Fovy";
const std::string keyInstrumentAspect = "Instrument.Aspect";
- const std::string keyProjObserver = "Projection.Observer";
- const std::string keyProjTarget = "Projection.Target";
- const std::string keyProjAberration = "Projection.Aberration";
-
- const std::string keySequenceDir = "Projection.Sequence";
- const std::string keySequenceType = "Projection.SequenceType";
const std::string keyTranslation = "DataInputTranslation";
- const std::string keyNeedsTextureMapDilation = "Projection.TextureMap";
- const std::string keyNeedsShadowing = "Projection.ShadowMap";
- const std::string keyTextureMapAspectRatio = "Projection.AspectRatio";
+ const std::string keyProjObserver = "Observer";
+ const std::string keyProjTarget = "Target";
+ const std::string keyProjAberration = "Aberration";
+
+ const std::string keySequenceDir = "Sequence";
+ const std::string keySequenceType = "SequenceType";
+
+ const std::string keyNeedsTextureMapDilation = "TextureMap";
+ const std::string keyNeedsShadowing = "ShadowMap";
+ const std::string keyTextureMapAspectRatio = "AspectRatio";
const std::string sequenceTypeImage = "image-sequence";
const std::string sequenceTypePlaybook = "playbook";
@@ -72,6 +74,94 @@ namespace openspace {
using ghoul::Dictionary;
using glm::ivec2;
+Documentation ProjectionComponent::Documentation() {
+ using namespace documentation;
+ return {
+ "Projection Component",
+ "newhorizons_projectioncomponent",
+ {
+ {
+ keyInstrument,
+ new StringAnnotationVerifier("A SPICE name of an instrument"),
+ "The instrument that is used to perform the projections",
+ Optional::No
+ },
+ {
+ keyInstrumentFovy,
+ new DoubleVerifier,
+ "The field of view in degrees along the y axis",
+ Optional::No
+ },
+ {
+ keyInstrumentAspect,
+ new DoubleVerifier,
+ "The aspect ratio of the instrument in relation between x and y axis",
+ Optional::No
+ },
+ {
+ keyProjObserver,
+ new StringAnnotationVerifier("A SPICE name of the observing object"),
+ "The observer that is doing the projection. This has to be a valid SPICE "
+ "name or SPICE integer.",
+ Optional::No
+ },
+ {
+ keyProjTarget,
+ new StringAnnotationVerifier("A SPICE name of the observed object"),
+ "The observed object that is projected on. This has to be a valid SPICE "
+ "name or SPICE integer.",
+ Optional::No
+ },
+ {
+ keyProjAberration,
+ new StringInListVerifier({
+ // from SpiceManager::AberrationCorrection::AberrationCorrection
+ "NONE", "LT", "LT+S", "CN", "CN+S", "XLT", "XLT+S", "XCN", "XCN+S"
+ }),
+ "The aberration correction that is supposed to be used for the "
+ "projection. The values for the correction correspond to the SPICE "
+ "definition as described in "
+ "ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/IDL/cspice/spkezr_c.html",
+ Optional::No
+ },
+ {
+ keyPotentialTargets,
+ new StringListVerifier,
+ "The list of potential targets that are involved with the image "
+ "projection",
+ Optional::Yes
+ },
+ {
+ keyNeedsTextureMapDilation,
+ new BoolVerifier,
+ "Determines whether a dilation step of the texture map has to be "
+ "performed after each projection. This is necessary if the texture of "
+ "the projected object is a texture map where the borders are not "
+ "touching. The default value is 'false'.",
+ Optional::Yes
+ },
+ {
+ keyNeedsShadowing,
+ new BoolVerifier,
+ "Determines whether the object requires a self-shadowing algorithm. This "
+ "is necessary if the object is concave and might cast a shadow on itself "
+ "during presentation. The default value is 'false'.",
+ Optional::Yes
+ },
+ {
+ keyTextureMapAspectRatio,
+ new DoubleVerifier,
+ "Sets the desired aspect ratio of the projected texture. This might be "
+ "necessary as planets usually have 2x1 aspect ratios, whereas this does "
+ "not hold for non-planet objects (comets, asteroids, etc). The default "
+ "value is '1.0'.",
+ Optional::Yes
+ }
+
+ }
+ };
+}
+
ProjectionComponent::ProjectionComponent()
: properties::PropertyOwner()
, _performProjection("performProjection", "Perform Projections", true)
@@ -96,7 +186,123 @@ ProjectionComponent::ProjectionComponent()
_applyTextureSize.onChange([this]() { _textureSizeDirty = true; });
}
-bool ProjectionComponent::initialize() {
+void ProjectionComponent::initialize(const ghoul::Dictionary& dictionary) {
+ documentation::testSpecificationAndThrow(
+ Documentation(),
+ dictionary,
+ "ProjectionComponent"
+ );
+ _instrumentID = dictionary.value(keyInstrument);
+ _projectorID = dictionary.value(keyProjObserver);
+ _projecteeID = dictionary.value(keyProjTarget);
+ _fovy = dictionary.value(keyInstrumentFovy);
+ _aspectRatio = dictionary.value(keyInstrumentAspect);
+
+ _aberration = SpiceManager::AberrationCorrection(
+ dictionary.value(keyProjAberration)
+ );
+
+ if (dictionary.hasKeyAndValue(keyPotentialTargets)) {
+ ghoul::Dictionary potentialTargets = dictionary.value(
+ keyPotentialTargets
+ );
+
+ _potentialTargets.reserve(potentialTargets.size());
+ for (int i = 1; i <= potentialTargets.size(); ++i) {
+ _potentialTargets.emplace_back(
+ potentialTargets.value(std::to_string(i))
+ );
+ }
+ }
+
+ if (dictionary.hasKeyAndValue(keyNeedsTextureMapDilation)) {
+ _dilation.isEnabled = dictionary.value(keyNeedsTextureMapDilation);
+ }
+
+ if (dictionary.hasKeyAndValue(keyNeedsShadowing)) {
+ _shadowing.isEnabled = dictionary.value(keyNeedsShadowing);
+ }
+
+ _projectionTextureAspectRatio = 1.f;
+ if (dictionary.hasKeyAndValue(keyTextureMapAspectRatio)) {
+ _projectionTextureAspectRatio =
+ static_cast(dictionary.value(keyTextureMapAspectRatio));
+ }
+
+ std::string name;
+ dictionary.getValue(SceneGraphNode::KeyName, name);
+
+ std::vector parsers;
+
+ std::string sequenceSource;
+ std::string sequenceType;
+ bool foundSequence = dictionary.getValue(keySequenceDir, sequenceSource);
+ if (foundSequence) {
+ sequenceSource = absPath(sequenceSource);
+
+ foundSequence = dictionary.getValue(keySequenceType, sequenceType);
+ //Important: client must define translation-list in mod file IFF playbook
+ if (dictionary.hasKey(keyTranslation)) {
+ ghoul::Dictionary translationDictionary;
+ //get translation dictionary
+ dictionary.getValue(keyTranslation, translationDictionary);
+
+ if (sequenceType == sequenceTypePlaybook) {
+ parsers.push_back(new HongKangParser(
+ name,
+ sequenceSource,
+ _projectorID,
+ translationDictionary,
+ _potentialTargets));
+ }
+ else if (sequenceType == sequenceTypeImage) {
+ parsers.push_back(new LabelParser(
+ name,
+ sequenceSource,
+ translationDictionary));
+ }
+ else if (sequenceType == sequenceTypeHybrid) {
+ //first read labels
+ parsers.push_back(new LabelParser(
+ name,
+ sequenceSource,
+ translationDictionary));
+
+ std::string _eventFile;
+ bool foundEventFile = dictionary.getValue("Projection.EventFile", _eventFile);
+ if (foundEventFile) {
+ //then read playbook
+ _eventFile = absPath(_eventFile);
+ parsers.push_back(new HongKangParser(
+ name,
+ _eventFile,
+ _projectorID,
+ translationDictionary,
+ _potentialTargets));
+ }
+ else {
+ LWARNING("No eventfile has been provided, please check modfiles");
+ }
+ }
+ else if (sequenceType == sequenceTypeInstrumentTimes) {
+ parsers.push_back(new InstrumentTimesParser(
+ name,
+ sequenceSource,
+ translationDictionary));
+ }
+
+ for (SequenceParser* parser : parsers) {
+ openspace::ImageSequencer::ref().runSequenceParser(parser);
+ delete parser;
+ }
+ }
+ else {
+ LWARNING("No playbook translation provided, please make sure all spice calls match playbook!");
+ }
+ }
+}
+
+bool ProjectionComponent::initializeGL() {
int maxSize = OpenGLCap.max2DTextureSize();
glm::ivec2 size;
@@ -193,131 +399,6 @@ bool ProjectionComponent::isReady() const {
return (_projectionTexture != nullptr);
}
-bool ProjectionComponent::initializeProjectionSettings(const Dictionary& dictionary) {
- bool completeSuccess = true;
- completeSuccess &= dictionary.getValue(keyInstrument, _instrumentID);
- completeSuccess &= dictionary.getValue(keyProjObserver, _projectorID);
- completeSuccess &= dictionary.getValue(keyProjTarget, _projecteeID);
- completeSuccess &= dictionary.getValue(keyInstrumentFovy, _fovy);
- completeSuccess &= dictionary.getValue(keyInstrumentAspect, _aspectRatio);
-
- ghoul_assert(completeSuccess, "All neccessary attributes not found in modfile");
-
- std::string a = "NONE";
- bool s = dictionary.getValue(keyProjAberration, a);
- _aberration = SpiceManager::AberrationCorrection(a);
- completeSuccess &= s;
- ghoul_assert(completeSuccess, "All neccessary attributes not found in modfile");
-
-
- if (dictionary.hasKeyAndValue(keyPotentialTargets)) {
- ghoul::Dictionary potentialTargets = dictionary.value(
- keyPotentialTargets
- );
-
- _potentialTargets.resize(potentialTargets.size());
- for (int i = 0; i < potentialTargets.size(); ++i) {
- std::string target;
- potentialTargets.getValue(std::to_string(i + 1), target);
- _potentialTargets[i] = target;
- }
- }
-
- if (dictionary.hasKeyAndValue(keyNeedsTextureMapDilation)) {
- _dilation.isEnabled = dictionary.value(keyNeedsTextureMapDilation);
- }
-
- if (dictionary.hasKeyAndValue(keyNeedsShadowing)) {
- _shadowing.isEnabled = dictionary.value(keyNeedsShadowing);
- }
-
- _projectionTextureAspectRatio = 1.f;
- if (dictionary.hasKeyAndValue(keyTextureMapAspectRatio)) {
- _projectionTextureAspectRatio =
- static_cast(dictionary.value(keyTextureMapAspectRatio));
- }
-
- return completeSuccess;
-}
-
-bool ProjectionComponent::initializeParser(const ghoul::Dictionary& dictionary) {
- bool completeSuccess = true;
-
- std::string name;
- dictionary.getValue(SceneGraphNode::KeyName, name);
-
- std::vector parsers;
-
- std::string sequenceSource;
- std::string sequenceType;
- bool foundSequence = dictionary.getValue(keySequenceDir, sequenceSource);
- if (foundSequence) {
- sequenceSource = absPath(sequenceSource);
-
- foundSequence = dictionary.getValue(keySequenceType, sequenceType);
- //Important: client must define translation-list in mod file IFF playbook
- if (dictionary.hasKey(keyTranslation)) {
- ghoul::Dictionary translationDictionary;
- //get translation dictionary
- dictionary.getValue(keyTranslation, translationDictionary);
-
- if (sequenceType == sequenceTypePlaybook) {
- parsers.push_back(new HongKangParser(
- name,
- sequenceSource,
- _projectorID,
- translationDictionary,
- _potentialTargets));
- }
- else if (sequenceType == sequenceTypeImage) {
- parsers.push_back(new LabelParser(
- name,
- sequenceSource,
- translationDictionary));
- }
- else if (sequenceType == sequenceTypeHybrid) {
- //first read labels
- parsers.push_back(new LabelParser(
- name,
- sequenceSource,
- translationDictionary));
-
- std::string _eventFile;
- bool foundEventFile = dictionary.getValue("Projection.EventFile", _eventFile);
- if (foundEventFile) {
- //then read playbook
- _eventFile = absPath(_eventFile);
- parsers.push_back(new HongKangParser(
- name,
- _eventFile,
- _projectorID,
- translationDictionary,
- _potentialTargets));
- }
- else {
- LWARNING("No eventfile has been provided, please check modfiles");
- }
- }
- else if (sequenceType == sequenceTypeInstrumentTimes) {
- parsers.push_back(new InstrumentTimesParser(
- name,
- sequenceSource,
- translationDictionary));
- }
-
- for(SequenceParser* parser : parsers){
- openspace::ImageSequencer::ref().runSequenceParser(parser);
- delete parser;
- }
- }
- else {
- LWARNING("No playbook translation provided, please make sure all spice calls match playbook!");
- }
- }
-
- return completeSuccess;
-}
-
void ProjectionComponent::imageProjectBegin() {
// keep handle to the current bound FBO
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO);
diff --git a/modules/newhorizons/util/projectioncomponent.h b/modules/newhorizons/util/projectioncomponent.h
index 6bae9afa6f..ef6b57cd4e 100644
--- a/modules/newhorizons/util/projectioncomponent.h
+++ b/modules/newhorizons/util/projectioncomponent.h
@@ -26,6 +26,8 @@
#define __PROJECTIONCOMPONENT_H__
#include
+
+#include
#include
#include
#include
@@ -48,14 +50,12 @@ class ProjectionComponent : public properties::PropertyOwner {
public:
ProjectionComponent();
- bool initialize();
+ void initialize(const ghoul::Dictionary& dictionary);
+ bool initializeGL();
bool deinitialize();
bool isReady() const;
- bool initializeProjectionSettings(const ghoul::Dictionary& dictionary);
- bool initializeParser(const ghoul::Dictionary& dictionary);
-
ghoul::opengl::Texture& depthTexture();
void imageProjectBegin();
void imageProjectEnd();
@@ -101,6 +101,8 @@ public:
float fieldOfViewY() const;
float aspectRatio() const;
+ static openspace::Documentation Documentation();
+
private:
bool generateProjectionLayerTexture(const glm::ivec2& size);
bool generateDepthTexture(const glm::ivec2& size);
From 708856dbf4f457bd5f8c95101ee73351be480404 Mon Sep 17 00:00:00 2001
From: Alexander Bock
Date: Fri, 28 Oct 2016 00:21:04 +0200
Subject: [PATCH 11/43] Fix double precision rendering for RenderablePlanet
---
modules/base/rendering/renderableplanet.cpp | 46 ++++++----
modules/base/shaders/nighttexture_fs.glsl | 2 +-
modules/base/shaders/nighttexture_vs.glsl | 17 ++--
modules/base/shaders/renderableplanet_fs.glsl | 84 +++++++++++++++++++
modules/base/shaders/renderableplanet_vs.glsl | 58 +++++++++++++
5 files changed, 178 insertions(+), 29 deletions(-)
create mode 100644 modules/base/shaders/renderableplanet_fs.glsl
create mode 100644 modules/base/shaders/renderableplanet_vs.glsl
diff --git a/modules/base/rendering/renderableplanet.cpp b/modules/base/rendering/renderableplanet.cpp
index eac80732c3..56b189f650 100644
--- a/modules/base/rendering/renderableplanet.cpp
+++ b/modules/base/rendering/renderableplanet.cpp
@@ -455,8 +455,8 @@ bool RenderablePlanet::initialize() {
// pscstandard
_programObject = renderEngine.buildRenderProgram(
"pscstandard",
- "${MODULE_BASE}/shaders/pscstandard_vs.glsl",
- "${MODULE_BASE}/shaders/pscstandard_fs.glsl");
+ "${MODULE_BASE}/shaders/renderableplanet_vs.glsl",
+ "${MODULE_BASE}/shaders/renderableplanet_fs.glsl");
if (!_programObject)
return false;
}
@@ -603,24 +603,29 @@ void RenderablePlanet::render(const RenderData& data) {
// activate shader
_programObject->activate();
+ glm::dmat4 modelTransform =
+ glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * // Translation
+ glm::dmat4(data.modelTransform.rotation) * // Spice rotation
+ glm::dmat4(glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)));
+
// scale the planet to appropriate size since the planet is a unit sphere
- glm::mat4 transform = glm::mat4(1);
+ //glm::mat4 transform = glm::mat4(1);
//earth needs to be rotated for that to work.
- glm::mat4 rot = glm::rotate(transform, static_cast(M_PI_2), glm::vec3(1, 0, 0));
- glm::mat4 roty = glm::rotate(transform, static_cast(M_PI_2), glm::vec3(0, -1, 0));
- glm::mat4 rotProp = glm::rotate(transform, glm::radians(static_cast(_rotation)), glm::vec3(0, 1, 0));
+ glm::dmat4 rot = glm::rotate(glm::dmat4(1.0), M_PI_2, glm::dvec3(1, 0, 0));
+ glm::dmat4 roty = glm::rotate(glm::dmat4(1.0), M_PI_2, glm::dvec3(0, -1, 0));
+ //glm::dmat4 rotProp = glm::rotate(glm::dmat4(1.0), glm::radians(static_cast(_rotation)), glm::dvec3(0, 1, 0));
+ modelTransform = modelTransform * rot * roty /** rotProp*/;
- for (int i = 0; i < 3; i++){
- for (int j = 0; j < 3; j++){
- transform[i][j] = static_cast(_stateMatrix[i][j]);
- }
- }
- transform = transform * rot * roty * rotProp;
+ glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform;
_programObject->setUniform("transparency", _alpha);
- _programObject->setUniform("ViewProjection", data.camera.viewProjectionMatrix());
- _programObject->setUniform("ModelTransform", transform);
+ _programObject->setUniform(
+ "modelViewProjectionTransform",
+ data.camera.projectionMatrix() * glm::mat4(modelViewTransform)
+ );
+ //_programObject->setUniform("ViewProjection", data.camera.viewProjectionMatrix());
+ _programObject->setUniform("ModelTransform", glm::mat4(modelTransform));
// Normal Transformation
glm::mat4 translateObjTrans = glm::translate(glm::mat4(1.0), data.position.vec3());
@@ -630,7 +635,7 @@ void RenderablePlanet::render(const RenderData& data) {
glm::mat4 ModelViewTrans = data.camera.viewMatrix() * scaleCamTrans *
- translateCamTrans * translateObjTrans * transform;
+ translateCamTrans * translateObjTrans * glm::mat4(modelTransform);
if (_atmosphereEnabled)
_programObject->setUniform("NormalTransform",
glm::transpose(glm::inverse(ModelViewTrans)));
@@ -762,7 +767,7 @@ void RenderablePlanet::render(const RenderData& data) {
/*glm::mat4 M = data.camera.viewMatrix() * scaleCamTrans * glm::mat4(data.camera.viewRotationMatrix()) *
translateCamTrans * obj2World * transform;
*/
- glm::mat4 M = glm::mat4(data.camera.combinedViewMatrix()) * scaleCamTrans * obj2World * transform;
+ glm::mat4 M = glm::mat4(data.camera.combinedViewMatrix()) * scaleCamTrans * obj2World * glm::mat4(modelTransform);
glm::mat4 completeInverse = glm::inverse(M);
@@ -770,7 +775,7 @@ void RenderablePlanet::render(const RenderData& data) {
_programObject->setUniform("projInverse", glm::inverse(data.camera.projectionMatrix()));
// This is camera position and planet position vector in object coordinates, in Km.
- glm::mat4 world2Obj = glm::inverse(obj2World * transform);
+ glm::mat4 world2Obj = glm::inverse(obj2World * glm::mat4(modelTransform));
glm::vec4 cameraPosObj = world2Obj * glm::vec4(data.camera.position().vec3() / 1000.0f, 1.0);
glm::vec4 planetPositionObj = world2Obj * glm::vec4(data.position.vec3() / 1000.0f, 1.0);
_programObject->setUniform("cameraPosObj", cameraPosObj);
@@ -840,7 +845,8 @@ void RenderablePlanet::render(const RenderData& data) {
void RenderablePlanet::update(const UpdateData& data) {
// set spice-orientation in accordance to timestamp
- _stateMatrix = SpiceManager::ref().positionTransformMatrix(_frame, "GALACTIC", data.time);
+ _stateMatrix = data.modelTransform.rotation;
+ //_stateMatrix = SpiceManager::ref().positionTransformMatrix(_frame, "GALACTIC", data.time);
_time = data.time;
}
@@ -849,6 +855,10 @@ void RenderablePlanet::loadTexture() {
if (_colorTexturePath.value() != "") {
_texture = std::move(ghoul::io::TextureReader::ref().loadTexture(absPath(_colorTexturePath)));
if (_texture) {
+ if (_texture->numberOfChannels() == 1) {
+ _texture->setSwizzleMask({ GL_RED, GL_RED, GL_RED, GL_RED });
+ }
+
LDEBUG("Loaded texture from '" << _colorTexturePath << "'");
_texture->uploadTexture();
diff --git a/modules/base/shaders/nighttexture_fs.glsl b/modules/base/shaders/nighttexture_fs.glsl
index dd527d5537..2096028f8f 100644
--- a/modules/base/shaders/nighttexture_fs.glsl
+++ b/modules/base/shaders/nighttexture_fs.glsl
@@ -76,7 +76,7 @@ Fragment getFragment() {
diffuse[3] = transparency;
frag.color = diffuse;
- frag.depth = depth;
+ frag.depth = vs_position.w;
return frag;
}
diff --git a/modules/base/shaders/nighttexture_vs.glsl b/modules/base/shaders/nighttexture_vs.glsl
index e278611ebb..8056fd63ad 100644
--- a/modules/base/shaders/nighttexture_vs.glsl
+++ b/modules/base/shaders/nighttexture_vs.glsl
@@ -36,27 +36,23 @@ out vec2 vs_st;
out vec4 vs_normal;
out vec4 vs_position;
-uniform mat4 ViewProjection;
uniform mat4 ModelTransform;
+uniform mat4 modelViewProjectionTransform;
uniform sampler2D heightTex;
uniform bool _hasHeightMap;
uniform float _heightExaggeration;
-
-void main()
-{
+void main() {
// set variables
vs_st = in_st;
- vs_position = in_position;
vec4 tmp = in_position;
// this is wrong for the normal. The normal transform is the transposed inverse of the model transform
vs_normal = normalize(ModelTransform * vec4(in_normal,0));
// vs_normal = vec4(in_normal, 0.0);
- vec4 position = pscTransform(tmp, ModelTransform);
- vs_position = tmp;
+ vec4 position = vec4(tmp.xyz * pow(10, tmp. w), 1.0);
if (_hasHeightMap) {
float height = texture(heightTex, in_st).r;
@@ -64,8 +60,9 @@ void main()
float displacementFactor = height * _heightExaggeration;
position.xyz = position.xyz + displacementDirection * displacementFactor;
}
-//
- position = ViewProjection * position;
+
+ position = modelViewProjectionTransform * position;
+ vs_position = z_normalization(position);
- gl_Position = z_normalization(position);
+ gl_Position = vs_position;
}
\ No newline at end of file
diff --git a/modules/base/shaders/renderableplanet_fs.glsl b/modules/base/shaders/renderableplanet_fs.glsl
new file mode 100644
index 0000000000..4304bb6b89
--- /dev/null
+++ b/modules/base/shaders/renderableplanet_fs.glsl
@@ -0,0 +1,84 @@
+/*****************************************************************************************
+ * *
+ * OpenSpace *
+ * *
+ * Copyright (c) 2014 *
+ * *
+ * 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. *
+ ****************************************************************************************/
+
+uniform vec4 campos;
+uniform vec4 objpos;
+//uniform vec3 camdir; // add this for specular
+
+uniform vec3 sun_pos;
+
+uniform bool _performShading = true;
+uniform float transparency;
+uniform int shadows;
+
+uniform float time;
+uniform sampler2D texture1;
+
+in vec2 vs_st;
+in vec4 vs_normal;
+in vec4 vs_position;
+
+#include "fragment.glsl"
+#include "PowerScaling/powerScaling_fs.hglsl"
+
+//#include "PowerScaling/powerScaling_vs.hglsl"
+Fragment getFragment() {
+ vec4 position = vs_position;
+ float depth = pscDepth(position);
+ vec4 diffuse = texture(texture1, vs_st);
+
+ Fragment frag;
+ if (_performShading) {
+ // directional lighting
+ vec3 origin = vec3(0.0);
+ vec4 spec = vec4(0.0);
+
+ vec3 n = normalize(vs_normal.xyz);
+ //vec3 e = normalize(camdir);
+ vec3 l_pos = vec3(sun_pos); // sun.
+ vec3 l_dir = normalize(l_pos-objpos.xyz);
+ float intensity = min(max(5*dot(n,l_dir), 0.0), 1);
+
+ float shine = 0.0001;
+
+ vec4 specular = vec4(0.5);
+ vec4 ambient = vec4(0.0,0.0,0.0,transparency);
+ /*
+ if(intensity > 0.f){
+ // halfway vector
+ vec3 h = normalize(l_dir + e);
+ // specular factor
+ float intSpec = max(dot(h,n),0.0);
+ spec = specular * pow(intSpec, shine);
+ }
+ */
+ diffuse = max(intensity * diffuse, ambient);
+ }
+
+ diffuse[3] = transparency;
+ frag.color = diffuse;
+ frag.depth = vs_position.w;
+
+ return frag;
+}
diff --git a/modules/base/shaders/renderableplanet_vs.glsl b/modules/base/shaders/renderableplanet_vs.glsl
new file mode 100644
index 0000000000..70873666b7
--- /dev/null
+++ b/modules/base/shaders/renderableplanet_vs.glsl
@@ -0,0 +1,58 @@
+/*****************************************************************************************
+ * *
+ * OpenSpace *
+ * *
+ * Copyright (c) 2014 *
+ * *
+ * 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. *
+ ****************************************************************************************/
+
+#version __CONTEXT__
+
+uniform mat4 ModelTransform;
+uniform mat4 modelViewProjectionTransform;
+
+layout(location = 0) in vec4 in_position;
+//in vec3 in_position;
+layout(location = 1) in vec2 in_st;
+layout(location = 2) in vec3 in_normal;
+
+out vec2 vs_st;
+out vec4 vs_normal;
+out vec4 vs_position;
+out float s;
+
+#include "PowerScaling/powerScaling_vs.hglsl"
+
+void main() {
+ // set variables
+ vs_st = in_st;
+ vec4 tmp = in_position;
+
+ // this is wrong for the normal. The normal transform is the transposed inverse of the model transform
+ vs_normal = normalize(ModelTransform * vec4(in_normal,0));
+ // vs_normal = vec4(in_normal, 0.0);
+
+ vec4 position = vec4(tmp.xyz * pow(10, tmp. w), 1.0);
+ position = modelViewProjectionTransform * position;
+
+ vs_position = z_normalization(position);
+
+
+ gl_Position = vs_position;
+}
\ No newline at end of file
From cb5f29612f4e487d5f1996e710abe86eec9f368e Mon Sep 17 00:00:00 2001
From: Alexander Bock
Date: Fri, 28 Oct 2016 00:23:21 +0200
Subject: [PATCH 12/43] Add Saturn moons to the data/scene Add jup260 torrent
download to the Jupiter system
---
.gitignore | 13 +++--
data/scene/jupiter/europa/europa.mod | 6 +--
data/scene/jupiter/jupiter/jup260.bsp.torrent | Bin 0 -> 16503 bytes
data/scene/jupiter/jupiter/jupiter.data | 3 ++
data/scene/saturn/dione/dione.data | 5 ++
data/scene/saturn/dione/dione.mod | 46 ++++++++++++++++++
data/scene/saturn/enceladus/enceladus.data | 5 ++
data/scene/saturn/enceladus/enceladus.mod | 46 ++++++++++++++++++
data/scene/saturn/iapetus/iapetus.data | 5 ++
data/scene/saturn/iapetus/iapetus.mod | 46 ++++++++++++++++++
data/scene/saturn/mimas/mimas.data | 5 ++
data/scene/saturn/mimas/mimas.mod | 46 ++++++++++++++++++
data/scene/saturn/rhea/rhea.data | 5 ++
data/scene/saturn/rhea/rhea.mod | 46 ++++++++++++++++++
data/scene/saturn/saturn/sat375.bsp.torrent | Bin 0 -> 11590 bytes
data/scene/saturn/{ => saturn}/saturn.data | 3 ++
data/scene/saturn/{ => saturn}/saturn.mod | 16 +++---
data/scene/saturn/tethys/tethys.data | 5 ++
data/scene/saturn/tethys/tethys.mod | 46 ++++++++++++++++++
data/scene/saturn/titan/titan.data | 5 ++
data/scene/saturn/titan/titan.mod | 46 ++++++++++++++++++
21 files changed, 383 insertions(+), 15 deletions(-)
create mode 100644 data/scene/jupiter/jupiter/jup260.bsp.torrent
create mode 100644 data/scene/saturn/dione/dione.data
create mode 100644 data/scene/saturn/dione/dione.mod
create mode 100644 data/scene/saturn/enceladus/enceladus.data
create mode 100644 data/scene/saturn/enceladus/enceladus.mod
create mode 100644 data/scene/saturn/iapetus/iapetus.data
create mode 100644 data/scene/saturn/iapetus/iapetus.mod
create mode 100644 data/scene/saturn/mimas/mimas.data
create mode 100644 data/scene/saturn/mimas/mimas.mod
create mode 100644 data/scene/saturn/rhea/rhea.data
create mode 100644 data/scene/saturn/rhea/rhea.mod
create mode 100644 data/scene/saturn/saturn/sat375.bsp.torrent
rename data/scene/saturn/{ => saturn}/saturn.data (55%)
rename data/scene/saturn/{ => saturn}/saturn.mod (96%)
create mode 100644 data/scene/saturn/tethys/tethys.data
create mode 100644 data/scene/saturn/tethys/tethys.mod
create mode 100644 data/scene/saturn/titan/titan.data
create mode 100644 data/scene/saturn/titan/titan.mod
diff --git a/.gitignore b/.gitignore
index 1006d42b46..eed900b2fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,7 +73,14 @@ data/scene/osirisrex/bennu/textures
data/scene/osirisrex/osirisrex/models
data/scene/osirisrex/osirisrex/textures
data/scene/pluto/textures
-data/scene/saturn/textures
+data/scene/saturn/dione/textures
+data/scene/saturn/enceladus/textures
+data/scene/saturn/iapetus/textures
+data/scene/saturn/mimas/textures
+data/scene/saturn/rhea/textures
+data/scene/saturn/saturn/textures
+data/scene/saturn/tethys/textures
+data/scene/saturn/titan/textures
data/scene/rosetta/67P/obj
data/scene/rosetta/67P/rosettaimages
data/scene/rosetta/67P/textures
@@ -90,11 +97,11 @@ data/scene/uranus/textures
data/scene/venus/textures
data/scene/volumetricmilkyway/milkyway
data/spice/DawnKernels
-data/spice/jup260.bsp
data/spice/de430_1850-2150.bsp
+data/spice/jup260.bsp
data/spice/MAR063.BSP
data/spice/NewHorizonsKernels
data/spice/nh_kernels
data/spice/OsirisRexKernels
data/spice/Rosetta
-
+data/spice/sat375.bsp
diff --git a/data/scene/jupiter/europa/europa.mod b/data/scene/jupiter/europa/europa.mod
index e4dc06dcbc..38d973e463 100644
--- a/data/scene/jupiter/europa/europa.mod
+++ b/data/scene/jupiter/europa/europa.mod
@@ -33,11 +33,7 @@ return {
Type = "SpiceRotation",
SourceFrame = "IAU_EUROPA",
DestinationFrame = "IAU_JUPITER",
- },
- Scale = {
- Type = "StaticScale",
- Scale = 1,
- },
+ }
}
},
-- EuropaTrail module
diff --git a/data/scene/jupiter/jupiter/jup260.bsp.torrent b/data/scene/jupiter/jupiter/jup260.bsp.torrent
new file mode 100644
index 0000000000000000000000000000000000000000..0c82073d38ad632e7c3de3c3330b204dfce18c91
GIT binary patch
literal 16503
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
F{{qko?@j;!
literal 0
HcmV?d00001
diff --git a/data/scene/jupiter/jupiter/jupiter.data b/data/scene/jupiter/jupiter/jupiter.data
index 34dcaf0900..b22e81119b 100644
--- a/data/scene/jupiter/jupiter/jupiter.data
+++ b/data/scene/jupiter/jupiter/jupiter.data
@@ -2,4 +2,7 @@ return {
FileRequest = {
{ Identifier = "jupiter_textures", Destination = "textures", Version = 1 }
},
+ TorrentFiles = {
+ { File = "jup260.bsp.torrent", Destination = "${SPICE}" },
+ }
}
\ No newline at end of file
diff --git a/data/scene/saturn/dione/dione.data b/data/scene/saturn/dione/dione.data
new file mode 100644
index 0000000000..924a314275
--- /dev/null
+++ b/data/scene/saturn/dione/dione.data
@@ -0,0 +1,5 @@
+return {
+ FileRequest = {
+ { Identifier = "dione_textures", Destination = "textures", Version = 1 }
+ },
+}
\ No newline at end of file
diff --git a/data/scene/saturn/dione/dione.mod b/data/scene/saturn/dione/dione.mod
new file mode 100644
index 0000000000..2cb996d841
--- /dev/null
+++ b/data/scene/saturn/dione/dione.mod
@@ -0,0 +1,46 @@
+return {
+ {
+ Name = "Dione",
+ Parent = "SaturnBarycenter",
+ Renderable = {
+ Type = "RenderablePlanet",
+ Frame = "IAU_DIONE",
+ Body = "DIONE",
+ Geometry = {
+ Type = "SimpleSphere",
+ Radius = { 0.563, 3 },
+ Segments = 50
+ },
+ Textures = {
+ Color = "textures/dione.jpg"
+ }
+ },
+ Transform = {
+ Translation = {
+ Type = "SpiceTranslation",
+ Body = "DIONE",
+ Observer = "SATURN BARYCENTER",
+ Kernels = "${OPENSPACE_DATA}/spice/sat375.bsp"
+ },
+ Rotation = {
+ Type = "SpiceRotation",
+ SourceFrame = "IAU_ENCELADUS",
+ DestinationFrame = "IAU_JUPITER"
+ }
+ }
+ },
+ {
+ Name = "DioneTrail",
+ Parent = "SaturnBarycenter",
+ Renderable = {
+ Type = "RenderableTrail",
+ Body = "DIONE",
+ Frame = "GALACTIC",
+ Observer = "SATURN BARYCENTER",
+ RGB = { 0.5, 0.3, 0.3 },
+ TropicalOrbitPeriod = 60,
+ EarthOrbitRatio = 0.0075,
+ DayLength = 0.9424218
+ }
+ }
+}
\ No newline at end of file
diff --git a/data/scene/saturn/enceladus/enceladus.data b/data/scene/saturn/enceladus/enceladus.data
new file mode 100644
index 0000000000..a31589f158
--- /dev/null
+++ b/data/scene/saturn/enceladus/enceladus.data
@@ -0,0 +1,5 @@
+return {
+ FileRequest = {
+ { Identifier = "enceladus_textures", Destination = "textures", Version = 1 }
+ },
+}
\ No newline at end of file
diff --git a/data/scene/saturn/enceladus/enceladus.mod b/data/scene/saturn/enceladus/enceladus.mod
new file mode 100644
index 0000000000..73684460ae
--- /dev/null
+++ b/data/scene/saturn/enceladus/enceladus.mod
@@ -0,0 +1,46 @@
+return {
+ {
+ Name = "Enceladus",
+ Parent = "SaturnBarycenter",
+ Renderable = {
+ Type = "RenderablePlanet",
+ Frame = "IAU_ENCELADUS",
+ Body = "ENCELADUS",
+ Geometry = {
+ Type = "SimpleSphere",
+ Radius = { 0.257, 3 },
+ Segments = 50
+ },
+ Textures = {
+ Color = "textures/enceladus.jpg"
+ }
+ },
+ Transform = {
+ Translation = {
+ Type = "SpiceTranslation",
+ Body = "ENCELADUS",
+ Observer = "SATURN BARYCENTER",
+ Kernels = "${OPENSPACE_DATA}/spice/sat375.bsp"
+ },
+ Rotation = {
+ Type = "SpiceRotation",
+ SourceFrame = "IAU_ENCELADUS",
+ DestinationFrame = "IAU_JUPITER"
+ }
+ }
+ },
+ {
+ Name = "EnceladusTrail",
+ Parent = "SaturnBarycenter",
+ Renderable = {
+ Type = "RenderableTrail",
+ Body = "ENCELADUS",
+ Frame = "GALACTIC",
+ Observer = "SATURN BARYCENTER",
+ RGB = { 0.5, 0.3, 0.3 },
+ TropicalOrbitPeriod = 60,
+ EarthOrbitRatio = 0.005,
+ DayLength = 0.9424218
+ }
+ }
+}
\ No newline at end of file
diff --git a/data/scene/saturn/iapetus/iapetus.data b/data/scene/saturn/iapetus/iapetus.data
new file mode 100644
index 0000000000..0db25d34c1
--- /dev/null
+++ b/data/scene/saturn/iapetus/iapetus.data
@@ -0,0 +1,5 @@
+return {
+ FileRequest = {
+ { Identifier = "iapetus_textures", Destination = "textures", Version = 1 }
+ },
+}
\ No newline at end of file
diff --git a/data/scene/saturn/iapetus/iapetus.mod b/data/scene/saturn/iapetus/iapetus.mod
new file mode 100644
index 0000000000..2f27987540
--- /dev/null
+++ b/data/scene/saturn/iapetus/iapetus.mod
@@ -0,0 +1,46 @@
+return {
+ {
+ Name = "Iapetus",
+ Parent = "SaturnBarycenter",
+ Renderable = {
+ Type = "RenderablePlanet",
+ Frame = "IAU_IAPETUS",
+ Body = "IAPETUS",
+ Geometry = {
+ Type = "SimpleSphere",
+ Radius = { 0.746, 3 },
+ Segments = 50
+ },
+ Textures = {
+ Color = "textures/iapetus.jpg"
+ }
+ },
+ Transform = {
+ Translation = {
+ Type = "SpiceTranslation",
+ Body = "IAPETUS",
+ Observer = "SATURN BARYCENTER",
+ Kernels = "${OPENSPACE_DATA}/spice/sat375.bsp"
+ },
+ Rotation = {
+ Type = "SpiceRotation",
+ SourceFrame = "IAU_ENCELADUS",
+ DestinationFrame = "IAU_JUPITER"
+ }
+ }
+ },
+ {
+ Name = "IapetusTrail",
+ Parent = "SaturnBarycenter",
+ Renderable = {
+ Type = "RenderableTrail",
+ Body = "IAPETUS",
+ Frame = "GALACTIC",
+ Observer = "SATURN BARYCENTER",
+ RGB = { 0.5, 0.3, 0.3 },
+ TropicalOrbitPeriod = 60,
+ EarthOrbitRatio = 0.1,
+ DayLength = 0.9424218
+ }
+ }
+}
\ No newline at end of file
diff --git a/data/scene/saturn/mimas/mimas.data b/data/scene/saturn/mimas/mimas.data
new file mode 100644
index 0000000000..01d792a8d4
--- /dev/null
+++ b/data/scene/saturn/mimas/mimas.data
@@ -0,0 +1,5 @@
+return {
+ FileRequest = {
+ { Identifier = "mimas_textures", Destination = "textures", Version = 1 }
+ },
+}
\ No newline at end of file
diff --git a/data/scene/saturn/mimas/mimas.mod b/data/scene/saturn/mimas/mimas.mod
new file mode 100644
index 0000000000..b73ae2843a
--- /dev/null
+++ b/data/scene/saturn/mimas/mimas.mod
@@ -0,0 +1,46 @@
+return {
+ {
+ Name = "Mimas",
+ Parent = "SaturnBarycenter",
+ Renderable = {
+ Type = "RenderablePlanet",
+ Frame = "IAU_MIMAS",
+ Body = "MIMAS",
+ Geometry = {
+ Type = "SimpleSphere",
+ Radius = { 0.28, 3 },
+ Segments = 50
+ },
+ Textures = {
+ Color = "textures/mimas.jpg"
+ }
+ },
+ Transform = {
+ Translation = {
+ Type = "SpiceTranslation",
+ Body = "MIMAS",
+ Observer = "SATURN BARYCENTER",
+ Kernels = "${OPENSPACE_DATA}/spice/sat375.bsp"
+ },
+ Rotation = {
+ Type = "SpiceRotation",
+ SourceFrame = "IAU_MIMAS",
+ DestinationFrame = "IAU_JUPITER"
+ }
+ }
+ },
+ {
+ Name = "MimasTrail",
+ Parent = "SaturnBarycenter",
+ Renderable = {
+ Type = "RenderableTrail",
+ Body = "MIMAS",
+ Frame = "GALACTIC",
+ Observer = "SATURN BARYCENTER",
+ RGB = { 0.5, 0.3, 0.3 },
+ TropicalOrbitPeriod = 60,
+ EarthOrbitRatio = 0.0025,
+ DayLength = 0.9424218
+ }
+ }
+}
\ No newline at end of file
diff --git a/data/scene/saturn/rhea/rhea.data b/data/scene/saturn/rhea/rhea.data
new file mode 100644
index 0000000000..9cf25ca314
--- /dev/null
+++ b/data/scene/saturn/rhea/rhea.data
@@ -0,0 +1,5 @@
+return {
+ FileRequest = {
+ { Identifier = "rhea_textures", Destination = "textures", Version = 1 }
+ },
+}
\ No newline at end of file
diff --git a/data/scene/saturn/rhea/rhea.mod b/data/scene/saturn/rhea/rhea.mod
new file mode 100644
index 0000000000..f5929f6b15
--- /dev/null
+++ b/data/scene/saturn/rhea/rhea.mod
@@ -0,0 +1,46 @@
+return {
+ {
+ Name = "Rhea",
+ Parent = "SaturnBarycenter",
+ Renderable = {
+ Type = "RenderablePlanet",
+ Frame = "IAU_RHEA",
+ Body = "RHEA",
+ Geometry = {
+ Type = "SimpleSphere",
+ Radius = { 0.765, 3 },
+ Segments = 50
+ },
+ Textures = {
+ Color = "textures/rhea.jpg"
+ }
+ },
+ Transform = {
+ Translation = {
+ Type = "SpiceTranslation",
+ Body = "RHEA",
+ Observer = "SATURN BARYCENTER",
+ Kernels = "${OPENSPACE_DATA}/spice/sat375.bsp"
+ },
+ Rotation = {
+ Type = "SpiceRotation",
+ SourceFrame = "IAU_ENCELADUS",
+ DestinationFrame = "IAU_JUPITER"
+ }
+ }
+ },
+ {
+ Name = "RheaTrail",
+ Parent = "SaturnBarycenter",
+ Renderable = {
+ Type = "RenderableTrail",
+ Body = "RHEA",
+ Frame = "GALACTIC",
+ Observer = "SATURN BARYCENTER",
+ RGB = { 0.5, 0.3, 0.3 },
+ TropicalOrbitPeriod = 60,
+ EarthOrbitRatio = 0.01,
+ DayLength = 0.9424218
+ }
+ }
+}
\ No newline at end of file
diff --git a/data/scene/saturn/saturn/sat375.bsp.torrent b/data/scene/saturn/saturn/sat375.bsp.torrent
new file mode 100644
index 0000000000000000000000000000000000000000..1939e82e2d976b74c202c3303e8cc70397f308f9
GIT binary patch
literal 11590
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