Merge branch 'master' into project/b612-asteroid-uncertainty

This commit is contained in:
Roxeena
2025-05-27 16:03:29 +02:00
497 changed files with 20202 additions and 29271 deletions
+6 -1
View File
@@ -41,7 +41,12 @@
[submodule "support/doxygen/css"]
path = support/doxygen/css
url = https://github.com/jothepro/doxygen-awesome-css.git
[submodule "modules/audio/ext/soloud"]
path = modules/audio/ext/soloud
url = https://github.com/jarikomppa/soloud
[submodule "modules/opensoundcontrol/ext/oscpack"]
path = modules/opensoundcontrol/ext/oscpack
url = https://github.com/OpenSpace/oscpack.git
[submodule "ext/json"]
path = ext/json
url = https://github.com/nlohmann/json
+3 -3
View File
@@ -157,15 +157,15 @@ add_custom_target(
ALL DEPENDS
"${CMAKE_CURRENT_BINARY_DIR}/__codegen.h"
)
add_dependencies(run_codegen codegen)
add_dependencies(run_codegen codegen-tool)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/__codegen.h"
COMMAND codegen ARGS "modules" "src"
COMMAND codegen-tool ARGS "modules" "src"
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
VERBATIM
)
set_target_properties(codegen-lib PROPERTIES FOLDER "support")
set_target_properties(codegen PROPERTIES FOLDER "support")
set_target_properties(codegen-tool PROPERTIES FOLDER "support")
set_target_properties(run_codegen PROPERTIES FOLDER "support")
+1 -1
View File
@@ -31,7 +31,7 @@
#include <ghoul/ghoul.h>
#include <ghoul/logging/logmanager.h>
int main(int argc, char** argv) {
int main(int, char** argv) {
using namespace openspace;
ghoul::logging::LogManager::initialize(
+1
View File
@@ -113,6 +113,7 @@ begin_header("Dependency: SGCT")
set(SGCT_TEXT OFF CACHE BOOL "" FORCE)
set(SGCT_DEP_INCLUDE_FREETYPE OFF CACHE BOOL "" FORCE)
set(SGCT_DEP_INCLUDE_FMT OFF CACHE BOOL "" FORCE)
set(SGCT_DEP_INCLUDE_JSON OFF CACHE BOOL "" FORCE)
set(SGCT_DEP_INCLUDE_SCN OFF CACHE BOOL "" FORCE)
set(SGCT_DEP_INCLUDE_CATCH2 OFF CACHE BOOL "" FORCE)
@@ -28,8 +28,10 @@ set(HEADER_FILES
include/backgroundimage.h
include/filesystemaccess.h
include/launcherwindow.h
include/notificationwindow.h
include/settingsdialog.h
include/splitcombobox.h
include/usericon.h
include/windowcolors.h
include/profile/actiondialog.h
include/profile/additionalscriptsdialog.h
@@ -59,8 +61,10 @@ set(SOURCE_FILES
src/backgroundimage.cpp
src/launcherwindow.cpp
src/filesystemaccess.cpp
src/notificationwindow.cpp
src/settingsdialog.cpp
src/splitcombobox.cpp
src/usericon.cpp
src/windowcolors.cpp
src/profile/actiondialog.cpp
src/profile/additionalscriptsdialog.cpp
@@ -0,0 +1,42 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2025 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___NOTIFICATIONWINDOW___H__
#define __OPENSPACE_UI_LAUNCHER___NOTIFICATIONWINDOW___H__
#include <QTextEdit>
#include <openspace/util/httprequest.h>
#include <memory>
class NotificationWindow final : public QTextEdit {
Q_OBJECT
public:
explicit NotificationWindow(QWidget* parent);
private:
std::unique_ptr<openspace::HttpMemoryDownload> _request;
};
#endif // __OPENSPACE_UI_LAUNCHER___NOTIFICATIONWINDOW___H__
@@ -0,0 +1,28 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2025 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <QIcon>
// Creates an icon that is used to represent user-generated content
QIcon userIcon();
@@ -27,7 +27,7 @@ LauncherWindow QLabel {
}
LauncherWindow QLabel#label_choose, QLabel#label_options {
color: rgb(255, 255, 255);
color: white;
font-size: 10pt;
}
@@ -37,11 +37,11 @@ LauncherWindow QLabel#clear {
LauncherWindow QLabel#version-info {
font-size: 10pt;
color: #dfdfdf;
color: rgb(225, 225, 225);
}
LauncherWindow QComboBox#config {
background: rgb(86, 86, 86);
background: rgb(96, 96, 96);
border: 1px solid rgb(225, 225, 225);
border-radius: 2px;
padding: 1px 18px 1px 3px;
@@ -49,7 +49,7 @@ LauncherWindow QComboBox#config {
font-size: 10pt;
font-family: Segoe UI;
font-weight: bold;
color: rgb(255, 255, 255);
color: white;
}
LauncherWindow QComboBox#config:hover {
@@ -61,6 +61,17 @@ LauncherWindow QComboBox#config:disabled {
color: rgb(225, 225, 225);
}
LauncherWindow QMenu#newprofile {
background: rgb(60, 60, 60);
min-width: 8em;
max-width: 8em;
color: white;
}
LauncherWindow QMenu#newprofile::item:selected {
background: rgb(110, 110, 110);
}
LauncherWindow QPushButton#start {
background: rgb(96, 96, 96);
border: 2px solid rgb(225, 225, 225);
@@ -69,34 +80,34 @@ LauncherWindow QPushButton#start {
font-size: 16pt;
font-weight: bold;
letter-spacing: 1px;
color: rgb(255, 255, 255);
color: white;
}
LauncherWindow QPushButton#start:hover {
background: rgb(120, 120, 120);
background: rgb(110, 110, 110);
}
LauncherWindow QPushButton#start:disabled {
background: rgb(175, 175, 175);
color: rgb(225, 225, 225);
background: rgb(60, 60, 60);
border: 1px solid rgb(60, 60, 60);
color: rgb(90, 90, 90);
}
LauncherWindow QPushButton#small {
background: rgb(86, 86, 86);
background: rgb(90, 90, 90);
border: 1px solid rgb(225, 225, 225);
border-radius: 2px;
border-style: outset;
min-height: 1em;
font-size: 10pt;
font-weight: bold;
color: rgb(255, 255, 255);
color: white;
}
LauncherWindow QPushButton#small:hover {
background: rgb(110, 110, 110);
}
LauncherWindow QPushButton#small:disabled {
background: rgb(204, 204, 204);
color: rgb(86, 86, 86);
background: rgb(60, 60, 60);
border: 1px solid rgb(60, 60, 60);
color: rgb(90, 90, 90);
}
LauncherWindow QPushButton#settings {
@@ -119,6 +130,12 @@ LauncherWindow QComboBox#config:focus
LauncherWindow QPushButton#settings:focus {
outline: 2px solid rgb(61, 189, 238);
}
LauncherWindow QTextEdit#notifications {
background-color: #242424;
color: #d7d7d7;
}
/*
* ProfileEdit
*/
@@ -195,6 +212,10 @@ ScriptlogDialog QListWidget {
min-width: 60em;
}
MarkNodesDialog QListWidget:focus {
border: 2px solid rgb(61, 189, 238);
}
/*
* Horizons dialog
*/
@@ -211,7 +232,7 @@ HorizonsDialog QLabel#thin {
}
HorizonsDialog QLabel#normal {
color: rgb(0, 0, 0);
color: black;
}
/*
@@ -26,6 +26,7 @@
#include "profile/profileedit.h"
#include "backgroundimage.h"
#include "notificationwindow.h"
#include "settingsdialog.h"
#include "splitcombobox.h"
#include <openspace/openspace.h>
@@ -35,6 +36,7 @@
#include <QFile>
#include <QKeyEvent>
#include <QLabel>
#include <QMenu>
#include <QMessageBox>
#include <QPushButton>
#include <QStandardItemModel>
@@ -45,8 +47,10 @@
using namespace openspace;
namespace {
constexpr int ScreenWidth = 480;
constexpr int ScreenHeight = 640;
constexpr int MainScreenWidth = 480;
constexpr int MainScreenHeight = 640;
constexpr int FullScreenWidth = MainScreenWidth;
constexpr int FullScreenHeight = 706;
constexpr int LeftRuler = 40;
constexpr int TopRuler = 80;
@@ -55,10 +59,12 @@ namespace {
constexpr int SmallItemWidth = 100;
constexpr int SmallItemHeight = SmallItemWidth / 4;
constexpr int NotificationShelfHeight = FullScreenHeight - MainScreenHeight;
constexpr int SettingsIconSize = 35;
namespace geometry {
constexpr QRect BackgroundImage(0, 0, ScreenWidth, ScreenHeight);
constexpr QRect BackgroundImage(0, 0, MainScreenWidth, MainScreenHeight);
constexpr QRect LogoImage(LeftRuler, TopRuler, ItemWidth, ItemHeight);
constexpr QRect ChooseLabel(LeftRuler + 10, TopRuler + 80, 151, 24);
constexpr QRect ProfileBox(LeftRuler, TopRuler + 110, ItemWidth, ItemHeight);
@@ -80,14 +86,19 @@ namespace {
LeftRuler, TopRuler + 400, ItemWidth, ItemHeight
);
constexpr QRect VersionString(
5, ScreenHeight - SmallItemHeight, ItemWidth, SmallItemHeight
5, MainScreenHeight - SmallItemHeight, ItemWidth, SmallItemHeight
);
constexpr QRect SettingsButton(
ScreenWidth - SettingsIconSize - 5,
ScreenHeight - SettingsIconSize - 5,
MainScreenWidth - SettingsIconSize - 5,
MainScreenHeight - SettingsIconSize - 5,
SettingsIconSize,
SettingsIconSize
);
constexpr QRect NotificationShelf(
0,
MainScreenHeight,
MainScreenWidth,
NotificationShelfHeight);
} // namespace geometry
@@ -132,7 +143,7 @@ LauncherWindow::LauncherWindow(bool profileEnabled, const Configuration& globalC
);
setWindowTitle("OpenSpace Launcher");
setFixedSize(ScreenWidth, ScreenHeight);
setFixedSize(FullScreenWidth, FullScreenHeight);
setAutoFillBackground(false);
{
@@ -163,6 +174,12 @@ LauncherWindow::LauncherWindow(bool profileEnabled, const Configuration& globalC
logoImage->setPixmap(QPixmap(":/images/openspace-horiz-logo-small.png"));
}
{
NotificationWindow* notificationWindow = new NotificationWindow(centralWidget);
notificationWindow->setGeometry(geometry::NotificationShelf);
notificationWindow->show();
}
//
// Profile chooser
//
@@ -173,30 +190,6 @@ LauncherWindow::LauncherWindow(bool profileEnabled, const Configuration& globalC
labelChoose->setObjectName("label_choose");
}
_editProfileButton = new QPushButton("Edit", centralWidget);
_editProfileButton->setObjectName("small");
_editProfileButton->setGeometry(geometry::EditProfileButton);
_editProfileButton->setCursor(Qt::PointingHandCursor);
_editProfileButton->setAutoDefault(true);
_editProfileButton->setAccessibleName("Edit profile");
connect(
_editProfileButton, &QPushButton::released,
this, &LauncherWindow::editProfile
);
{
QPushButton* newProfileButton = new QPushButton("New", centralWidget);
newProfileButton->setObjectName("small");
newProfileButton->setGeometry(geometry::NewProfileButton);
newProfileButton->setCursor(Qt::PointingHandCursor);
newProfileButton->setAutoDefault(true);
newProfileButton->setAccessibleName("New profile");
connect(
newProfileButton, &QPushButton::released,
this, &LauncherWindow::newProfile
);
}
// Creating the profile box _after_ the Edit and New buttons as the comboboxes
// `selectionChanged` signal will trigger that will try to make changes to the edit
// button
@@ -222,8 +215,8 @@ LauncherWindow::LauncherWindow(bool profileEnabled, const Configuration& globalC
_profileBox->setObjectName("config");
_profileBox->setGeometry(geometry::ProfileBox);
_profileBox->setAccessibleName("Choose profile");
_profileBox->populateList(globalConfig.profile);
_profileBox->setEnabled(profileEnabled);
_profileBox->populateList(globalConfig.profile);
connect(
_profileBox, &SplitComboBox::selectionChanged,
this, &LauncherWindow::selectProfile
@@ -233,12 +226,58 @@ LauncherWindow::LauncherWindow(bool profileEnabled, const Configuration& globalC
this, &LauncherWindow::updateStartButton
);
_editProfileButton = new QPushButton("Edit", centralWidget);
_editProfileButton->setObjectName("small");
_editProfileButton->setGeometry(geometry::EditProfileButton);
_editProfileButton->setCursor(Qt::PointingHandCursor);
_editProfileButton->setAutoDefault(true);
_editProfileButton->setAccessibleName("Edit profile");
connect(
_editProfileButton, &QPushButton::released,
this, &LauncherWindow::editProfile
);
{
// Set up the default value for the edit button
std::string selection = std::get<1>(_profileBox->currentSelection());
_editProfileButton->setEnabled(std::filesystem::exists(selection));
}
{
QPushButton* newProfileButton = new QPushButton("New", centralWidget);
newProfileButton->setObjectName("small");
newProfileButton->setGeometry(geometry::NewProfileButton);
newProfileButton->setCursor(Qt::PointingHandCursor);
newProfileButton->setAutoDefault(true);
newProfileButton->setAccessibleName("New profile");
connect(
newProfileButton, &QPushButton::released,
this, &LauncherWindow::newProfile
);
QMenu* menu = new QMenu(this);
menu->setObjectName("newprofile");
menu->setToolTipsVisible(true);
QAction* newEmpty = new QAction("Empty profile", this);
newEmpty->setToolTip("Creates a new empty profile without any existing content");
connect(
newEmpty, &QAction::triggered,
this, &LauncherWindow::newProfile
);
QAction* newFromCurrent = new QAction("Duplicate profile", this);
newFromCurrent->setToolTip(
"Creates a duplicate of the currently selected profile. This duplicate can "
"be edited and saved under a new name, or if it was a user profile be "
"overwritten"
);
connect(
newFromCurrent, &QAction::triggered,
this, &LauncherWindow::editProfile
);
menu->addActions({ newEmpty, newFromCurrent });
newProfileButton->setMenu(menu);
}
//
@@ -250,31 +289,6 @@ LauncherWindow::LauncherWindow(bool profileEnabled, const Configuration& globalC
optionsLabel->setObjectName("label_options");
}
_editWindowButton = new QPushButton("Edit", centralWidget);
_editWindowButton->setVisible(true);
_editWindowButton->setObjectName("small");
_editWindowButton->setGeometry(geometry::EditWindowButton);
_editWindowButton->setCursor(Qt::PointingHandCursor);
_editWindowButton->setAutoDefault(true);
_editWindowButton->setAccessibleName("Edit window configuration");
connect(
_editWindowButton, &QPushButton::released,
this, &LauncherWindow::editConfiguration
);
{
QPushButton* newWindowButton = new QPushButton("New", centralWidget);
newWindowButton->setObjectName("small");
newWindowButton->setGeometry(geometry::NewWindowButton);
newWindowButton->setCursor(Qt::PointingHandCursor);
newWindowButton->setAutoDefault(true);
newWindowButton->setAccessibleName("New window configuration");
connect(
newWindowButton, &QPushButton::released,
this, &LauncherWindow::newConfiguration
);
}
_windowConfigBox = new SplitComboBox(
centralWidget,
_userConfigPath,
@@ -313,11 +327,36 @@ LauncherWindow::LauncherWindow(bool profileEnabled, const Configuration& globalC
this, &LauncherWindow::updateStartButton
);
_editWindowButton = new QPushButton("Edit", centralWidget);
_editWindowButton->setVisible(true);
_editWindowButton->setObjectName("small");
_editWindowButton->setGeometry(geometry::EditWindowButton);
_editWindowButton->setCursor(Qt::PointingHandCursor);
_editWindowButton->setAutoDefault(true);
_editWindowButton->setAccessibleName("Edit window configuration");
connect(
_editWindowButton, &QPushButton::released,
this, &LauncherWindow::editConfiguration
);
{
// Set up the default value for the edit button
std::string selection = std::get<1>(_windowConfigBox->currentSelection());
_editWindowButton->setEnabled(std::filesystem::exists(selection));
}
{
QPushButton* newWindowButton = new QPushButton("New", centralWidget);
newWindowButton->setObjectName("small");
newWindowButton->setGeometry(geometry::NewWindowButton);
newWindowButton->setCursor(Qt::PointingHandCursor);
newWindowButton->setAutoDefault(true);
newWindowButton->setAccessibleName("New window configuration");
connect(
newWindowButton, &QPushButton::released,
this, &LauncherWindow::newConfiguration
);
}
//
@@ -391,7 +430,19 @@ void LauncherWindow::selectProfile(std::optional<std::string> selection) {
ghoul_assert(selection.has_value(), "No special item in the profiles");
if (selection.has_value()) {
// Having the `if` statement here to satisfy the MSVC code analysis
_editProfileButton->setEnabled(std::filesystem::exists(*selection));
// Enable the Edit button only for the user profiles
const bool isUser = selection->starts_with(_userProfilePath.string());
_editProfileButton->setEnabled(isUser);
if (isUser) {
_editProfileButton->setToolTip("");
}
else {
_editProfileButton->setToolTip(
"Cannot edit the selected profile as it is one of the built-in profiles"
);
}
}
}
@@ -407,8 +458,7 @@ void LauncherWindow::selectConfiguration(std::optional<std::string> selection) {
// If the configuration is a default configuration, we don't allow editing
_editWindowButton->setEnabled(false);
_editWindowButton->setToolTip(
"Cannot edit since the selected configuration is one of the files "
"provided by OpenSpace"
"Cannot edit the selected configuration as it is one of the built-in profiles"
);
}
else {
@@ -598,19 +648,21 @@ void LauncherWindow::openProfileEditor(const std::string& profile, bool isUserPr
&ProfileEdit::raiseExitWindow,
[&editor, &savePath, &p, &profile]() {
const std::string origPath = std::format("{}{}.profile", savePath, profile);
// If this is a new profile we want to prompt the user
if (!std::filesystem::exists(origPath)) {
// If this is a new profile we want to prompt the user, but only if the user
// actually changed something. If it is still an empty profile, there is no
// need to save it
if (!std::filesystem::exists(origPath) && *p != Profile()) {
editor.promptUserOfUnsavedChanges();
return;
}
// Check if the profile is the same as current existing file
if (std::filesystem::exists(origPath) && *p != Profile(origPath)) {
editor.promptUserOfUnsavedChanges();
return;
}
// Check if the profile is the same as current existing file
if (*p != Profile(origPath)) {
editor.promptUserOfUnsavedChanges();
}
else {
editor.closeWithoutSaving();
}
// If we got this far, we can safely close the dialog without saving anything
editor.closeWithoutSaving();
}
);
@@ -0,0 +1,231 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2025 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "notificationwindow.h"
#include <openspace/openspace.h>
#include <openspace/engine/settings.h>
#include <openspace/util/httprequest.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/assert.h>
#include <ghoul/misc/stringhelper.h>
#include <QGuiApplication>
#include <QStyleHints>
#include <QTimer>
#include <scn/scan.h>
#include <date/date.h>
#include <string_view>
#include <vector>
using namespace openspace;
namespace {
struct Entry {
std::string date;
std::string text;
};
// Parses a single notification entry out of the list of lines
Entry parseEntry(std::vector<std::string>::const_iterator& curr) {
ghoul_assert(!curr->empty(), "First line must not be empty");
std::string date = *curr;
std::string text;
do {
curr++;
text += *curr;
} while (!curr->empty());
curr++;
return { std::move(date), std::move(text) };
}
std::vector<Entry> parseEntries(const std::string& data) {
std::vector<Entry> entries;
std::vector<std::string> lines = ghoul::tokenizeString(data, '\n');
if (lines.empty() || lines[0].empty()) {
// The notification file is empty and we don't want to show anything
return entries;
}
std::vector<std::string>::const_iterator curr = lines.cbegin();
while (curr != lines.end()) {
Entry e = parseEntry(curr);
entries.push_back(std::move(e));
}
return entries;
}
std::string formatEntry(const Entry& e, date::year_month_day lastStartedDate) {
auto r = scn::scan<int, int, int>(e.date, "{}-{}-{}");
ghoul_assert(r, "Invalid date");
auto& [year, month, day] = r->values();
const date::year_month_day ymd = date::year_month_day(
date::year(year),
date::month(month),
date::day(day)
);
QColor text = QGuiApplication::palette().text().color();
text = text.darker();
if (date::sys_days(ymd) < date::sys_days(lastStartedDate)) {
const QColor textColor = QColor(120, 120, 120);
return std::format(
"<tr>"
"<td width='15%'>"
"<font color='#{2:x}{3:x}{4:x}'>{0}</font>"
"</td>"
"<td width='85%' align='left'>"
"<font color='#{2:x}{3:x}{4:x}'>{1}</font>"
"</td>"
"</tr>",
e.date, e.text, textColor.red(), textColor.green(), textColor.blue()
);
}
else {
return std::format(
"<tr>"
"<td width='15%'>"
"{0}"
"</td>"
"<td width='85%' align='left'>"
"{1}"
"</td>"
"</tr>",
e.date, e.text
);
}
}
} // namespace
NotificationWindow::NotificationWindow(QWidget* parent)
: QTextEdit(parent)
{
setAcceptRichText(true);
setReadOnly(true);
setFocusPolicy(Qt::NoFocus);
setObjectName("notifications");
std::string URL = std::format(
"https://raw.githubusercontent.com/OpenSpace/Notifications/refs/heads/master/"
"{}.txt",
OPENSPACE_IS_RELEASE_BUILD ? OPENSPACE_VERSION_NUMBER : "master"
);
_request = std::make_unique<HttpMemoryDownload>(
URL,
ghoul::logging::LogLevel::NoLogging
);
_request->start(std::chrono::seconds(1));
// The download has a timeout of 1s, so after 1250ms we'll definitely have answer.
constexpr int TimeOut = 1250;
QTimer::singleShot(TimeOut, [this](){
while (!_request->hasSucceeded() && !_request->hasFailed()) {
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
if (_request->hasFailed()) {
LWARNINGC("Notification", "Failed to retrieve notification file");
// The download has failed for some reason
return;
}
// 1. Get the downloaded data
const std::vector<char>& data = _request->downloadedData();
std::string notificationText = std::string(data.begin(), data.end());
// 2. Parse the retrieved data into entries
std::vector<Entry> entries = parseEntries(notificationText);
// 3. Filter the entries to not show anything that is older than 6 months
const date::year_month_day now = date::year_month_day(
floor<date::days>(std::chrono::system_clock::now())
);
std::erase_if(
entries,
[now](const Entry& e) {
auto r = scn::scan<int, int, int>(e.date, "{}-{}-{}");
if (!r) {
return false;
}
auto& [year, month, day] = r->values();
const date::year_month_day ymd = date::year_month_day(
date::year(year),
date::month(month),
date::day(day)
);
const std::chrono::days diff = date::sys_days(now) - date::sys_days(ymd);
const bool older = diff.count() > (365 / 2);
return older;
}
);
// 4. Format the entries into a table format
Settings settings = loadSettings();
// Picking a date as the default date that is far enough in the past
date::year_month_day lastStart = date::year_month_day(
date::year(2000),
date::month(1),
date::day(1)
);
if (settings.lastStartedDate.has_value()) {
auto r = scn::scan<int, int, int>(*settings.lastStartedDate, "{}-{}-{}");
if (r) {
auto& [year, month, day] = r->values();
lastStart = date::year_month_day(
date::year(year),
date::month(month),
date::day(day)
);
}
}
std::string text = std::accumulate(
entries.begin(),
entries.end(),
std::string(),
[&lastStart](std::string t, const Entry& e) {
return std::format(
"{}{}",
std::move(t), formatEntry(e, lastStart)
);
}
);
// Add the HTML-like table attributes
text = std::format("<table border='0'>{}</table>", std::move(text));
// 5. Set the text
QString t = QString::fromStdString(text);
setText(t);
});
}
@@ -917,7 +917,7 @@ openspace::HorizonsFile HorizonsDialog::handleAnswer(nlohmann::json& answer) {
}
// Return a new file with the result
return openspace::HorizonsFile(filePath, *result);
return openspace::HorizonsFile(filePath, result->get<std::string>());
}
bool HorizonsDialog::handleResult(openspace::HorizonsResultCode& result) {
@@ -1084,6 +1084,23 @@ bool HorizonsDialog::handleResult(openspace::HorizonsResultCode& result) {
std::filesystem::remove(_horizonsFile.file());
break;
}
case HorizonsResultCode::News: {
std::string msg = std::format(
"The target '{}' is too simlar to the Horizons command 'NEWS'",
_targetName
);
appendLog(msg, HorizonsDialog::LogLevel::Error);
msg = std::format(
"Try to use '@{}' as target to avoid false positive matches with the "
"Horizons command 'NEWS'", _targetName
);
appendLog(msg, HorizonsDialog::LogLevel::Info);
styleLabel(_targetLabel, IsDirty::Yes);
std::filesystem::remove(_horizonsFile.file());
break;
}
case HorizonsResultCode::MultipleObserver: {
std::string msg = std::format(
"Multiple matches were found for observer '{}'", _observerName
@@ -55,8 +55,8 @@ void SettingsDialog::createWidgets() {
// | Profile |
// | Starting Profile: | [oooooooooooooooooooo] |
// | [] Keep Last Profile |
// | Configuration |
// | Starting Configuration: | [oooooooooooooooooooo] |
// | Window Options |
// | Starting Window Option: | [oooooooooooooooooooo] |
// | [] Keep Last Configuration |
// | User Interface |
// | Property Visibility | DDDDDDDDDDDDDDDDDDDDD> |
@@ -108,9 +108,14 @@ void SettingsDialog::createWidgets() {
"If this setting is checked, the application will remember the profile that "
"was loaded into OpenSpace and will use it at the next startup as well"
);
connect(
_rememberLastProfile,
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
&QCheckBox::checkStateChanged,
#else // ^^^^ >=6.7.0 // !WIN32 <6.7.0
&QCheckBox::stateChanged,
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
[this]() {
if (_rememberLastProfile->isChecked()) {
_currentEdit.rememberLastProfile = true;
@@ -129,11 +134,11 @@ void SettingsDialog::createWidgets() {
layout->addWidget(new Line(), 3, 0, 1, 2);
{
QLabel* label = new QLabel("Configuration");
QLabel* label = new QLabel("Window Configuration");
label->setObjectName("heading");
layout->addWidget(label, 4, 0, 1, 2);
QLabel* conf = new QLabel("Starting Configuration");
QLabel* conf = new QLabel("Starting Window Configuration");
conf->setToolTip(
"With this setting, you can choose a window configuration that will be "
"loaded the next time you start the application"
@@ -166,7 +171,11 @@ void SettingsDialog::createWidgets() {
);
connect(
_rememberLastConfiguration,
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
&QCheckBox::checkStateChanged,
#else // ^^^^ >=6.7.0 // !WIN32 <6.7.0
&QCheckBox::stateChanged,
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
[this]() {
if (_rememberLastConfiguration->isChecked()) {
_currentEdit.rememberLastConfiguration = true;
@@ -241,7 +250,11 @@ void SettingsDialog::createWidgets() {
);
connect(
_bypassLauncher,
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
&QCheckBox::checkStateChanged,
#else // ^^^^ >=6.7.0 // !WIN32 <6.7.0
&QCheckBox::stateChanged,
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
[this]() {
if (_bypassLauncher->isChecked()) {
_currentEdit.bypassLauncher = _bypassLauncher->isChecked();
@@ -313,7 +326,11 @@ void SettingsDialog::createWidgets() {
);
connect(
_mrf.isEnabled,
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
&QCheckBox::checkStateChanged,
#else // ^^^^ >=6.7.0 // !WIN32 <6.7.0
&QCheckBox::stateChanged,
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
[this]() {
if (_mrf.isEnabled->isChecked()) {
_currentEdit.mrf.isEnabled = _mrf.isEnabled->isChecked();
@@ -32,7 +32,7 @@ MonitorBox::MonitorBox(QRect widgetSize, const std::vector<QRect>& monitorResolu
QWidget* parent)
: QWidget(parent)
{
constexpr float MarginFractionWidgetSize = 0.05f;
constexpr float MarginFractionWidgetSize = 0.02f;
//
// Calculate the collective size of the monitors
@@ -132,7 +132,7 @@ void MonitorBox::paintEvent(QPaintEvent*) {
_monitorDimensionsScaled[i].top() + 24.0
);
QFont f = QFont("Arial");
f.setPixelSize(24);
f.setPixelSize(18);
painter.setFont(f);
painter.drawText(textPos, "Primary");
}
@@ -148,6 +148,9 @@ void MonitorBox::paintEvent(QPaintEvent*) {
std::clamp(x, 0.0, static_cast<double>(size().width()) - 10.0),
std::clamp(y, 20.0, static_cast<double>(size().height()))
);
QFont f = QFont("Arial");
f.setPixelSize(18);
painter.setFont(f);
painter.drawText(p, QString::number(i + 1));
}
@@ -103,7 +103,7 @@ SgctEdit::SgctEdit(sgct::config::Cluster cluster, std::string configName,
//
// Monitor widget at the top of the window
{
constexpr QRect MonitorWidgetSize = QRect(0, 0, 500, 500);
constexpr QRect MonitorWidgetSize = QRect(0, 0, 350, 350);
MonitorBox* monitorBox = new MonitorBox(MonitorWidgetSize, monitorSizes);
layout->addWidget(monitorBox, 0, Qt::AlignCenter);
@@ -131,6 +131,7 @@ SgctEdit::SgctEdit(sgct::config::Cluster cluster, std::string configName,
layout->addWidget(settingsContainer);
QBoxLayout* settingsLayout = new QVBoxLayout(settingsContainer);
settingsLayout->setContentsMargins(0, 0, 0, 0);
settingsLayout->setSpacing(0);
//
@@ -149,9 +150,6 @@ SgctEdit::SgctEdit(sgct::config::Cluster cluster, std::string configName,
//
// Orientation specification
QLabel* labelOrientation = new QLabel("Orientation");
settingsLayout->addWidget(labelOrientation);
QWidget* orientationContainer = new QWidget;
settingsLayout->addWidget(orientationContainer);
QGridLayout* layoutWindow = new QGridLayout(orientationContainer);
@@ -177,9 +175,6 @@ SgctEdit::SgctEdit(sgct::config::Cluster cluster, std::string configName,
validatorPitch->setNotation(QDoubleValidator::StandardNotation);
_linePitch->setValidator(validatorPitch);
layoutWindow->addWidget(_linePitch, 0, 1);
QLabel* range = new QLabel("Range [-90, 90] in degrees");
layoutWindow->addWidget(range, 0, 2);
}
{
const QString rollTip = "Roll or bank: negative numbers rotate the camera "
@@ -188,7 +183,7 @@ SgctEdit::SgctEdit(sgct::config::Cluster cluster, std::string configName,
QLabel* labelRoll = new QLabel("Roll");
labelRoll->setToolTip(rollTip);
layoutWindow->addWidget(labelRoll, 1, 0);
layoutWindow->addWidget(labelRoll, 0, 2);
_lineRoll = new QLineEdit;
_lineRoll->setText(QString::number(glm::degrees(glm::roll(q))));
@@ -196,10 +191,7 @@ SgctEdit::SgctEdit(sgct::config::Cluster cluster, std::string configName,
QDoubleValidator* validatorRoll = new QDoubleValidator(-360.0, 360.0, 15);
validatorRoll->setNotation(QDoubleValidator::StandardNotation);
_lineRoll->setValidator(validatorRoll);
layoutWindow->addWidget(_lineRoll, 1, 1);
QLabel* range = new QLabel("Range [-360, 360] in degrees");
layoutWindow->addWidget(range, 1, 2);
layoutWindow->addWidget(_lineRoll, 0, 3);
}
{
const QString yawTip = "Yaw, heading, or azimuth: negative numbers pan the "
@@ -209,7 +201,7 @@ SgctEdit::SgctEdit(sgct::config::Cluster cluster, std::string configName,
QLabel* labelYaw = new QLabel;
labelYaw->setText("Yaw");
labelYaw->setToolTip(yawTip);
layoutWindow->addWidget(labelYaw, 2, 0);
layoutWindow->addWidget(labelYaw, 0, 4);
_lineYaw = new QLineEdit;
_lineYaw->setText(QString::number(glm::degrees(glm::yaw(q))));
@@ -217,10 +209,15 @@ SgctEdit::SgctEdit(sgct::config::Cluster cluster, std::string configName,
QDoubleValidator* validatorYaw = new QDoubleValidator(-180.0, 180.0, 15, this);
validatorYaw->setNotation(QDoubleValidator::StandardNotation);
_lineYaw->setValidator(validatorYaw);
layoutWindow->addWidget(_lineYaw, 2, 1);
layoutWindow->addWidget(_lineYaw, 0, 5);
}
QLabel* range = new QLabel("Range [-180, 180] in degrees");
layoutWindow->addWidget(range, 2, 2);
{
QLabel* info = new QLabel(
"The allowed ranges for pitch is [-90, 90], for roll [-180, 180], and for "
"yaw [-360, 360]."
);
layoutWindow->addWidget(info, 1, 0, 1, 6);
}
@@ -162,7 +162,7 @@ WindowControl::WindowControl(int monitorIndex, int windowIndex,
_windowName = new QLineEdit;
_windowName->setToolTip(tip);
layout->addWidget(_windowName, 1, 1, 1, 7);
layout->addWidget(_windowName, 1, 1, 1, 3);
}
const QString tip = "The monitor where this window is located";
@@ -188,9 +188,9 @@ WindowControl::WindowControl(int monitorIndex, int windowIndex,
// potential nullpointer accesses elsewhere in the code
QLabel* labelLocation = new QLabel("Monitor");
labelLocation->setToolTip(tip);
layout->addWidget(labelLocation, 2, 0);
layout->addWidget(labelLocation, 1, 4);
layout->addWidget(_monitor, 2, 1, 1, 7);
layout->addWidget(_monitor, 1, 5, 1, 4);
}
//
@@ -24,8 +24,10 @@
#include "splitcombobox.h"
#include "usericon.h"
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/assert.h>
#include <QPainter>
#include <QStandardItemModel>
SplitComboBox::SplitComboBox(QWidget* parent, std::filesystem::path userPath,
@@ -42,6 +44,8 @@ SplitComboBox::SplitComboBox(QWidget* parent, std::filesystem::path userPath,
, _fileFilter(std::move(fileFilter))
, _createTooltip(std::move(createTooltip))
{
setCursor(Qt::PointingHandCursor);
connect(
this,
QOverload<int>::of(&QComboBox::currentIndexChanged),
@@ -66,14 +70,25 @@ void SplitComboBox::populateList(const std::string& preset) {
// Clear the previously existing entries since we might call this function again
clear();
// Create "icons" that we use to indicate whether an item is built-in or user content
QIcon icon = userIcon();
//
// Special item (if it was specified)
if (!_specialFirst.empty()) {
addItem(
QString::fromStdString(_specialFirst),
QString::fromStdString(_specialFirst)
);
if (_specialFirst.starts_with(_userPath.string())) {
addItem(
icon,
QString::fromStdString(_specialFirst),
QString::fromStdString(_specialFirst)
);
}
else {
addItem(
QString::fromStdString(_specialFirst),
QString::fromStdString(_specialFirst)
);
}
}
@@ -94,6 +109,7 @@ void SplitComboBox::populateList(const std::string& preset) {
// Display the relative path, but store the full path in the user data segment
addItem(
icon,
QString::fromStdString(relPath.string()),
QString::fromStdString(p.string())
);
@@ -0,0 +1,43 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2025 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "usericon.h"
#include <QPainter>
QIcon userIcon() {
QPixmap px = QPixmap(40, 50);
px.fill(Qt::transparent);
QPainter painter = QPainter(&px);
painter.setBrush(QColor(183, 211, 149, 255));
painter.drawEllipse(0, 10, 38, 38);
QFont f = QFont("Arial");
f.setPixelSize(28);
f.setBold(true);
painter.setFont(f);
painter.drawText(0, 10, 40, 40, Qt::AlignCenter, "U");
return QIcon(px);
}
+122 -32
View File
@@ -29,6 +29,9 @@
#include <openspace/engine/settings.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/joystickinputstate.h>
#include <openspace/util/progressbar.h>
#include <openspace/util/task.h>
#include <openspace/util/taskloader.h>
#include <openspace/openspace.h>
#include <ghoul/format.h>
#include <ghoul/ghoul.h>
@@ -53,6 +56,7 @@
#include <sgct/projection/nonlinearprojection.h>
#include <sgct/user.h>
#include <sgct/window.h>
#include <date/date.h>
#include <stb_image.h>
#include <tracy/Tracy.hpp>
#include <iostream>
@@ -99,6 +103,11 @@ glm::ivec2 currentDrawResolution;
Window* FirstOpenVRWindow = nullptr;
#endif
// This value is specified from the commandline options and kept around to be run after
// everything has been initialized. It's going to be std::nullopt unless a user wants to
// run a task
std::optional<std::string> taskToRun;
//
// SPOUT-support
//
@@ -400,6 +409,40 @@ void mainInitFunc(GLFWwindow*) {
// Query joystick status, those connected before start up
checkJoystickStatus();
if (taskToRun.has_value()) {
// If a task was specified on the commandline line, we are loading that file and
// executing everything within
TaskLoader loader;
std::vector<std::unique_ptr<Task>> tasks = loader.tasksFromFile(*taskToRun);
size_t nTasks = tasks.size();
if (nTasks == 1) {
LINFO("Task queue has 1 item");
}
else {
LINFO(std::format("Task queue has {} items", tasks.size()));
}
for (size_t i = 0; i < tasks.size(); i++) {
Task& task = *tasks[i].get();
LINFO(std::format(
"Performing task {} out of {}: {}",
i + 1, tasks.size(), task.description()
));
ProgressBar progressBar = ProgressBar(100);
auto onProgress = [&progressBar](float progress) {
progressBar.print(static_cast<int>(progress * 100.f));
};
task.perform(onProgress);
}
std::cout << "Done performing tasks" << std::endl;
// Done with the tasks, so we can terminate
Engine::instance().terminate();
}
LTRACE("main::mainInitFunc(end)");
}
@@ -924,24 +967,40 @@ void setSgctDelegateFunctions() {
return Engine::instance().windows().front()->id();
};
sgctDelegate.nameForWindow = [](int windowIdx) {
ZoneScoped;
ghoul_assert(
windowIdx >= 0 &&
windowIdx < Engine::instance().windows().size(),
"Invalid window index"
);
return Engine::instance().windows()[windowIdx]->name();
};
sgctDelegate.openGLProcedureAddress = [](const char* func) {
ZoneScoped;
return glfwGetProcAddress(func);
};
sgctDelegate.getHorizFieldOfView = []() {
sgctDelegate.horizFieldOfView = [](int windowIdx) {
ZoneScoped;
return static_cast<double>(
Engine::instance().windows().front()->horizFieldOfViewDegrees()
ghoul_assert(
windowIdx >= 0 &&
windowIdx < Engine::instance().windows().size(),
"Invalid window index"
);
return Engine::instance().windows()[windowIdx]->horizFieldOfViewDegrees();
};
sgctDelegate.setHorizFieldOfView = [](float hFovDeg) {
sgctDelegate.setHorizFieldOfView = [](int windowIdx, float hFovDeg) {
ZoneScoped;
for (std::unique_ptr<sgct::Window> const& w : Engine::instance().windows()) {
w->setHorizFieldOfView(hFovDeg);
}
ghoul_assert(
windowIdx >= 0 &&
windowIdx < Engine::instance().windows().size(),
"Invalid window index"
);
Engine::instance().windows()[windowIdx]->setHorizFieldOfView(hFovDeg);
};
#ifdef WIN32
sgctDelegate.getNativeWindowHandle = [](size_t windowIndex) -> void* {
@@ -1070,6 +1129,12 @@ void setSgctDelegateFunctions() {
int main(int argc, char* argv[]) {
ZoneScoped;
// For debugging purposes: Enforce Light Mode in Qt
// qputenv("QT_QPA_PLATFORM", "windows:darkmode=0");
// For debugging purposes: Enforce Dark Mode in Qt
// qputenv("QT_QPA_PLATFORM", "windows:darkmode=1");
#ifdef OPENSPACE_BREAK_ON_FLOATING_POINT_EXCEPTION
_clearfp();
_controlfp(_controlfp(0, 0) & ~(_EM_ZERODIVIDE | _EM_OVERFLOW), _MCW_EM);
@@ -1119,41 +1184,56 @@ int main(int argc, char* argv[]) {
CommandlineArguments commandlineArguments;
parser.addCommand(std::make_unique<ghoul::cmdparser::SingleCommand<std::string>>(
commandlineArguments.configuration, "--file", "-f",
commandlineArguments.configuration,
"--file",
"-f",
"Provides the path to the OpenSpace configuration file. Only the '${TEMPORARY}' "
"path token is available and any other path has to be specified relative to the "
"current working directory"
));
parser.addCommand(std::make_unique<ghoul::cmdparser::SingleCommand<std::string>>(
commandlineArguments.windowConfig, "--config", "-c",
commandlineArguments.windowConfig,
"--config",
"-c",
"Specifies the window configuration file that should be used to start OpenSpace "
"and that will override whatever is specified in the `openspace.cfg` or the "
"settings. This value can include path tokens, so for example "
"`${CONFIG}/single.json` is a valid value."
));
parser.addCommand(std::make_unique<ghoul::cmdparser::SingleCommand<std::string>>(
commandlineArguments.profile, "--profile", "-p",
commandlineArguments.profile,
"--profile",
"-p",
"Specifies the profile that should be used to start OpenSpace and that overrides "
"the profile specified in the `openspace.cfg` and the settings."
));
parser.addCommand(std::make_unique<ghoul::cmdparser::SingleCommand<std::string>>(
commandlineArguments.propertyVisibility, "--propertyVisibility", "",
commandlineArguments.propertyVisibility,
"--propertyVisibility",
"",
"Specifies UI visibility settings for properties that this OpenSpace is using. "
"This value overrides the values specified in the `openspace.cfg` and the "
"settings and also the environment variable, if that value is provided. Allowed "
"values for this parameter are: `Developer`, `AdvancedUser`, `User`, and "
"`NoviceUser`."
));
parser.addCommand(std::make_unique<ghoul::cmdparser::SingleCommand<std::string>>(
commandlineArguments.task,
"--task",
"-t",
"Specifies a task that will be run after OpenSpace has been initialized. Once "
"the task finishes, the application will automatically close again. All other "
"commandline arguments are ignored, if a task is specified."
));
parser.addCommand(std::make_unique<ghoul::cmdparser::SingleCommandZeroArguments>(
commandlineArguments.bypassLauncher, "--bypassLauncher", "-b",
commandlineArguments.bypassLauncher,
"--bypassLauncher",
"-b",
"Specifies whether the Launcher should be shown at startup or not. This value "
"overrides the value specified in the `openspace.cfg` and the settings."
));
// setCommandLine returns a reference to the vector that will be filled later
const std::vector<std::string>& sgctArguments = parser.setCommandLine(
{ argv, argv + argc }
);
parser.setCommandLine({ argv, argv + argc });
try {
const bool showHelp = parser.execute();
@@ -1166,8 +1246,16 @@ int main(int argc, char* argv[]) {
LFATALC(e.component, e.message);
exit(EXIT_FAILURE);
}
// Take an actual copy of the arguments
std::vector<std::string> arguments = sgctArguments;
if (commandlineArguments.task.has_value()) {
// If a task was specified, we want to overwrite the used window and profile and
// not display the launcher
commandlineArguments.windowConfig = "${CONFIG}/single.json";
commandlineArguments.profile = "empty";
commandlineArguments.bypassLauncher = true;
taskToRun = *commandlineArguments.task;
}
//
// Set up SGCT functions for window delegate
@@ -1451,21 +1539,20 @@ int main(int argc, char* argv[]) {
settings.configuration =
isGeneratedWindowConfig ? "" : global::configuration->windowConfiguration;
const date::year_month_day now = date::year_month_day(
floor<date::days>(std::chrono::system_clock::now())
);
settings.lastStartedDate = std::format(
"{}-{:0>2}-{:0>2}",
static_cast<int>(now.year()),
static_cast<unsigned>(now.month()),
static_cast<unsigned>(now.day())
);
saveSettings(settings, findSettings());
}
// Prepend the outgoing sgctArguments with the program name
// as well as the configuration file that sgct is supposed to use
arguments.insert(arguments.begin(), argv[0]);
arguments.insert(arguments.begin() + 1, "-config");
arguments.insert(
arguments.begin() + 2,
absPath(global::configuration->windowConfiguration).string()
);
// Need to set this before the creation of the sgct::Engine
Log::instance().setLogToConsole(false);
Log::instance().setShowTime(false);
Log::instance().setShowLogLevel(false);
@@ -1475,9 +1562,14 @@ int main(int argc, char* argv[]) {
glfwWindowHint(GLFW_STENCIL_BITS, 8);
#endif
std::filesystem::path winConf =
commandlineArguments.windowConfig.has_value() ?
*commandlineArguments.windowConfig :
global::configuration->windowConfiguration;
// Determining SGCT configuration file
LINFO(std::format(
"SGCT Configuration file: {}", absPath(global::configuration->windowConfiguration)
"SGCT Configuration file: {}", absPath(winConf)
));
@@ -1488,9 +1580,7 @@ int main(int argc, char* argv[]) {
LDEBUG("Loading cluster information");
config::Cluster cluster;
try {
cluster = loadCluster(
absPath(global::configuration->windowConfiguration).string()
);
cluster = loadCluster(absPath(winConf).string());
}
catch (const std::runtime_error& e) {
LFATALC("main", e.what());
+1 -1
View File
@@ -19,7 +19,7 @@
"type": "FisheyeProjection",
"fov": 180.0,
"quality": "1k",
"tilt": 27.0,
"tilt": 90.0,
"background": { "r": 0.1, "g": 0.1, "b": 0.1, "a": 1.0 }
}
}
+1 -1
View File
@@ -43,7 +43,7 @@
"type": "FisheyeProjection",
"fov": 180.0,
"quality": "1k",
"tilt": 27.0,
"tilt": 90.0,
"background": { "r": 0.1, "g": 0.1, "b": 0.1, "a": 1.0 }
}
}
+299 -6
View File
@@ -1,6 +1,299 @@
asset.require("actions/trails/toggle_all_trails")
asset.require("actions/trails/toggle_trails_planets_moons")
asset.require("actions/planets/planet_lighting")
asset.require("actions/system/undo_event_fades")
asset.require("actions/trails/toggle_all_minor_moon_trails")
asset.require("actions/trails/on_off_all_minor_moons")
local ToggleShutdown = {
Identifier = "os.ToggleShutdown",
Name = "Toggle shutdown",
Command = "openspace.toggleShutdown()",
Documentation = [[
Toggles the shutdown that will stop OpenSpace after a grace period. Press again to
cancel the shutdown during this period]],
GuiPath = "/System",
IsLocal = true
}
-- Friction actions
local ToggleRotationFriction = {
Identifier = "os.ToggleRotationFriction",
Name = "Toggle rotation friction",
Command = [[openspace.invertBooleanProperty("NavigationHandler.OrbitalNavigator.Friction.RotationalFriction")]],
Documentation = [[Toggles the rotational friction of the camera. If it is disabled, the
camera rotates around the focus object indefinitely]],
GuiPath = "/Navigation",
IsLocal = true
}
local ToggleZoomFriction = {
Identifier = "os.ToggleZoomFriction",
Name = "Toggle zoom friction",
Command = [[openspace.invertBooleanProperty("NavigationHandler.OrbitalNavigator.Friction.ZoomFriction")]],
Documentation = [[Toggles the zoom friction of the camera. If it is disabled, the camera
rises up from or closes in towards the focus object indefinitely]],
GuiPath = "/Navigation",
IsLocal = true
}
local ToggleRollFriction = {
Identifier = "os.ToggleRollFriction",
Name = "Toggle roll friction",
Command = [[openspace.invertBooleanProperty("NavigationHandler.OrbitalNavigator.Friction.RollFriction")]],
Documentation = [[Toggles the roll friction of the camera. If it is disabled, the camera
rolls around its own axis indefinitely]],
GuiPath = "/Navigation",
IsLocal = true
}
-- UI actions
local ToggleMainGui = {
Identifier = "os.ToggleMainGui",
Name = "Toggle main GUI",
Command = [[openspace.invertBooleanProperty("Modules.CefWebGui.Visible")]],
Documentation = "Toggles the main GUI",
GuiPath = "/System/GUI",
IsLocal = true
}
local ToggleNativeUi = {
Identifier = "os.ToggleNativeUi",
Name = "Show native GUI",
Command = [[openspace.invertBooleanProperty("Modules.ImGUI.Enabled")]],
Documentation = "Shows or hides the native UI",
GuiPath = "/System/GUI",
IsLocal = true
}
local ReloadGui = {
Identifier = "os.ReloadGui",
Name = "Reload GUI",
Command = [[openspace.setPropertyValueSingle("Modules.CefWebGui.Reload", nil)]],
Documentation = "Reloads the GUI",
GuiPath = "/System/GUI",
IsLocal = true
}
-- Rendering actions
local TakeScreenshot = {
Identifier = "os.TakeScreenshot",
Name = "Take screenshot",
Command = "openspace.takeScreenshot()",
Documentation = [[Saves the contents of the screen to a file in the ${SCREENSHOTS}
directory]],
GuiPath = "/System/Rendering",
IsLocal = true
}
local FadeToBlack = {
Identifier = "os.FadeToBlack",
Name = "Fade to/from black",
Command = [[
if openspace.propertyValue("RenderEngine.BlackoutFactor") > 0.5 then
openspace.setPropertyValueSingle("RenderEngine.BlackoutFactor", 0.0, 3)
else
openspace.setPropertyValueSingle("RenderEngine.BlackoutFactor", 1.0, 3)
end
]],
Documentation = [[Toggles the fade to black within 3 seconds or shows the rendering
after 3 seconds]],
GuiPath = "/Rendering",
IsLocal = false
}
local ToggleOverlays = {
Identifier = "os.ToggleOverlays",
Name = "Toggle dashboard and overlays",
Command = [[
local isEnabled = openspace.propertyValue("Dashboard.IsEnabled")
openspace.setPropertyValueSingle("Dashboard.IsEnabled", not isEnabled)
openspace.setPropertyValueSingle("RenderEngine.ShowLog", not isEnabled)
openspace.setPropertyValueSingle("RenderEngine.ShowVersion", not isEnabled)
]],
Documentation = "Toggles the dashboard and overlays",
GuiPath = "/System/GUI",
IsLocal = true
}
local ToggleMasterRendering = {
Identifier = "os.ToggleMasterRendering",
Name = "Toggle rendering on master",
Command = [[openspace.invertBooleanProperty("RenderEngine.DisableMasterRendering")]],
Documentation = "Toggles the rendering on master",
GuiPath = "/System/Rendering",
IsLocal = true
}
-- Time actions
local TogglePauseInterpolated = {
Identifier = "os.TogglePauseInterpolated",
Name = "Toggle pause (interpolate)",
Command = "openspace.time.pauseToggleViaKeyboard()",
Documentation = "Smoothly starts and stops the simulation time",
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local TogglePauseImmediate = {
Identifier = "os.TogglePauseImmediate",
Name = "Toggle pause (immediate)",
Command = "openspace.time.togglePause()",
Documentation = "Immediately starts and stops the simulation time",
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local NextDeltaStepInterpolate = {
Identifier = "os.NextDeltaStepInterpolate",
Name = "Next simulation time step (interpolate)",
Command = "openspace.time.interpolateNextDeltaTimeStep()",
Documentation = [[Smoothly interpolates the simulation speed to the next simulation time
step, if one exists]],
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local NextDeltaStepImmediate = {
Identifier = "os.NextDeltaStepImmediate",
Name = "Next simulation time step (immediate)",
Command = "openspace.time.setNextDeltaTimeStep()",
Documentation = [[Immediately set the simulation speed to the next simulation time step,
if one exists]],
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local PreviousDeltaStepInterpolate = {
Identifier = "os.PreviousDeltaStepInterpolate",
Name = "Previous simulation time step (interpolate)",
Command = "openspace.time.interpolatePreviousDeltaTimeStep()",
Documentation = [[Smoothly interpolates the simulation speed to the previous simulation
time step, if one exists]],
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local PreviousDeltaStepImmediate = {
Identifier = "os.PreviousDeltaStepImmediate",
Name = "Previous simulation time step (immediate)",
Command = "openspace.time.setPreviousDeltaTimeStep()",
Documentation = [[Immediately set the simulation speed to the previous simulation time
step, if one exists]],
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local RealTimeDeltaStepInterpolate = {
Identifier = "os.RealTimeDeltaStepInterpolate",
Name = "Reset the simulation time to realtime (interpolate)",
Command = "openspace.time.interpolateDeltaTime(1)",
Documentation = "Smoothly interpolate the simulation speed to match real-time speed",
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local RealTimeDeltaStepImmediate = {
Identifier = "os.RealTimeDeltaStepImmediate",
Name = "Reset the simulation time to realtime (immediate)",
Command = "openspace.time.setDeltaTime(1)",
Documentation = "Immediately set the simulation speed to match real-time speed",
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
asset.onInitialize(function()
openspace.action.registerAction(ToggleShutdown)
-- Friction
openspace.action.registerAction(ToggleRotationFriction)
openspace.action.registerAction(ToggleZoomFriction)
openspace.action.registerAction(ToggleRollFriction)
-- UI
openspace.action.registerAction(ToggleMainGui)
openspace.action.registerAction(ToggleNativeUi)
openspace.action.registerAction(ReloadGui)
-- Rendering
openspace.action.registerAction(TakeScreenshot)
openspace.action.registerAction(FadeToBlack)
openspace.action.registerAction(ToggleOverlays)
openspace.action.registerAction(ToggleMasterRendering)
-- Time
openspace.action.registerAction(TogglePauseInterpolated)
openspace.action.registerAction(TogglePauseImmediate)
openspace.action.registerAction(NextDeltaStepInterpolate)
openspace.action.registerAction(NextDeltaStepImmediate)
openspace.action.registerAction(PreviousDeltaStepInterpolate)
openspace.action.registerAction(PreviousDeltaStepImmediate)
openspace.action.registerAction(RealTimeDeltaStepInterpolate)
openspace.action.registerAction(RealTimeDeltaStepImmediate)
end)
asset.onDeinitialize(function()
-- Time
openspace.action.removeAction(RealTimeDeltaStepImmediate)
openspace.action.removeAction(RealTimeDeltaStepInterpolate)
openspace.action.removeAction(PreviousDeltaStepImmediate)
openspace.action.removeAction(PreviousDeltaStepInterpolate)
openspace.action.removeAction(NextDeltaStepImmediate)
openspace.action.removeAction(NextDeltaStepInterpolate)
openspace.action.removeAction(TogglePauseImmediate)
openspace.action.removeAction(TogglePauseInterpolated)
-- Rendering
openspace.action.removeAction(ToggleMasterRendering)
openspace.action.removeAction(ToggleOverlays)
openspace.action.removeAction(FadeToBlack)
openspace.action.removeAction(TakeScreenshot)
-- UI
openspace.action.removeAction(ReloadGui)
openspace.action.removeAction(ToggleNativeUi)
openspace.action.removeAction(ToggleMainGui)
-- Friction
openspace.action.removeAction(ToggleRollFriction)
openspace.action.removeAction(ToggleZoomFriction)
openspace.action.removeAction(ToggleRotationFriction)
openspace.action.removeAction(ToggleShutdown)
end)
asset.export("ToggleShutdown", ToggleShutdown.Identifier)
asset.export("ToggleRotationFriction", ToggleRotationFriction.Identifier)
asset.export("ToggleZoomFriction", ToggleZoomFriction.Identifier)
asset.export("ToggleRollFriction", ToggleRollFriction.Identifier)
asset.export("ToggleMainGui", ToggleMainGui.Identifier)
asset.export("ToggleNativeUi", ToggleNativeUi.Identifier)
asset.export("ReloadGui", ReloadGui.Identifier)
asset.export("TakeScreenshot", TakeScreenshot.Identifier)
asset.export("FadeToBlack", FadeToBlack.Identifier)
asset.export("ToggleOverlays", ToggleOverlays.Identifier)
asset.export("ToggleMasterRendering", ToggleMasterRendering.Identifier)
asset.export("TogglePauseInterpolated", TogglePauseInterpolated.Identifier)
asset.export("TogglePauseImmediate", TogglePauseImmediate.Identifier)
asset.export("NextDeltaStepInterpolate", NextDeltaStepInterpolate.Identifier)
asset.export("NextDeltaStepImmediate", NextDeltaStepImmediate.Identifier)
asset.export("PreviousDeltaStepInterpolate", PreviousDeltaStepInterpolate.Identifier)
asset.export("PreviousDeltaStepImmediate", PreviousDeltaStepImmediate.Identifier)
asset.export("RealTimeDeltaStepInterpolate", RealTimeDeltaStepInterpolate.Identifier)
asset.export("RealTimeDeltaStepImmediate", RealTimeDeltaStepImmediate.Identifier)
asset.meta = {
Name = "Actions - Default",
Description = "Asset providing default actions that are useful in every profile",
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license"
}
+54 -3
View File
@@ -61,7 +61,7 @@ local LookingNorth = {
Command = [[
local currentNavState = openspace.navigation.getNavigationState()
local newNavState = {
Pitch = math.pi / 2.0,
Pitch = math.pi,
Anchor = currentNavState["Anchor"],
Yaw = currentNavState["Yaw"],
Position = currentNavState["Position"],
@@ -74,13 +74,36 @@ local LookingNorth = {
IsLocal = false
}
local LookingEast = {
Identifier = "os.nightsky.LookingEast",
Name = "Looking East",
Command = [[
local lat, lon, alt = openspace.globebrowsing.geoPositionForCamera()
local lon_rad = math.rad(lon)
local upx = -math.sin(lon_rad)
local upy = math.cos(lon_rad)
local currentNavState = openspace.navigation.getNavigationState()
local newNavState = {
Pitch = math.pi,
Anchor = currentNavState["Anchor"],
Yaw = currentNavState["Yaw"],
Position = currentNavState["Position"],
Up = { upx, upy, 0 }
}
openspace.navigation.setNavigationState(newNavState)
]],
Documentation = "Sets the view looking up and East.",
GuiPath = "/Night Sky/View",
IsLocal = false
}
local LookingSouth = {
Identifier = "os.nightsky.LookingSouth",
Name = "Looking South",
Command = [[
local currentNavState = openspace.navigation.getNavigationState()
local newNavState = {
Pitch = math.pi / 2.0,
Pitch = math.pi,
Anchor = currentNavState["Anchor"],
Yaw = currentNavState["Yaw"],
Position = currentNavState["Position"],
@@ -88,22 +111,48 @@ local LookingSouth = {
}
openspace.navigation.setNavigationState(newNavState)
]],
Documentation = "Sets the view for a horizon looking South.",
Documentation = "Sets the view looking up and South.",
GuiPath = "/Night Sky/View",
IsLocal = false
}
local LookingWest = {
Identifier = "os.nightsky.LookingWest",
Name = "Looking West",
Command = [[
local lat, lon, alt = openspace.globebrowsing.geoPositionForCamera()
local lon_rad = math.rad(lon)
local upx = math.sin(lon_rad)
local upy = -math.cos(lon_rad)
local currentNavState = openspace.navigation.getNavigationState()
local newNavState = {
Pitch = math.pi,
Anchor = currentNavState["Anchor"],
Yaw = currentNavState["Yaw"],
Position = currentNavState["Position"],
Up = { upx, upy, 0 }
}
openspace.navigation.setNavigationState(newNavState)
]],
Documentation = "Sets the view looking up and West.",
GuiPath = "/Night Sky/View",
IsLocal = false
}
asset.onInitialize(function()
openspace.action.registerAction(LookUp)
openspace.action.registerAction(LevelHorizonYaw)
openspace.action.registerAction(LevelHorizonPitch)
openspace.action.registerAction(LookingNorth)
openspace.action.registerAction(LookingEast)
openspace.action.registerAction(LookingSouth)
openspace.action.registerAction(LookingWest)
end)
asset.onDeinitialize(function()
openspace.action.removeAction(LookingWest)
openspace.action.removeAction(LookingSouth)
openspace.action.removeAction(LookingEast)
openspace.action.removeAction(LookingNorth)
openspace.action.removeAction(LevelHorizonPitch)
openspace.action.removeAction(LevelHorizonYaw)
@@ -114,4 +163,6 @@ asset.export("LookUp", LookUp.Identifier)
asset.export("LevelHorizonYaw", LevelHorizonYaw.Identifier)
asset.export("LevelHorizonPitch", LevelHorizonPitch.Identifier)
asset.export("LookingNorth", LookingNorth.Identifier)
asset.export("LookingEast", LookingEast.Identifier)
asset.export("LookingSouth", LookingSouth.Identifier)
asset.export("LookingWest", LookingWest.Identifier)
@@ -0,0 +1,66 @@
local AddSunTrail = {
Identifier = "os.nightsky.AddSunTrail",
Name = "Add sun trail",
Command = [[
local date
if is_declared("args") then
if (args.Date == "NOW") then
date = openspace.time.currentWallTime()
elseif (args.Date == "UTC") then
date = openspace.time.UTC()
else
date = args.Date
end
else
date = openspace.time.UTC()
end
local datePlus = openspace.time.advancedTime(date, '1d')
date = string.sub(date, 1, string.find(date, "T") - 1)
datePlus = string.sub(datePlus, 1, string.find(datePlus, "T") - 1)
local SunTrailEarth = {
Identifier = "SunTrailEarth" .. date,
Parent = "Earth",
Renderable = {
Type = "RenderableTrailTrajectory",
Translation = {
Type = "SpiceTranslation",
Target = "SUN",
Observer = "EARTH",
Frame = "IAU_EARTH",
},
EnableFade = false,
StartTime = date,
EndTime = datePlus,
SampleInterval = 1000,
ShowFullTrail = true,
Color = { 0.9, 1.0, 0.0 },
},
Tag = { "sun_trail" },
GUI = {
Name = "Sun Trail " .. date,
Path = "/Night Sky/Sun Trails",
}
}
openspace.addSceneGraphNode(SunTrailEarth)
]],
Documentation = [[
Adds a trail for the sun, if an argument is provided, that date will be used instead of now
]],
GuiPath = "/Night Sky/Sun Trails",
IsLocal = false
}
asset.onInitialize(function()
openspace.action.registerAction(AddSunTrail)
end)
asset.onDeinitialize(function()
openspace.action.removeAction(AddSunTrail)
end)
asset.export("AddSunTrail", AddSunTrail.Identifier)
+112
View File
@@ -0,0 +1,112 @@
local textures = asset.resource({
Name = "Cardinal Directions Textures",
Type = "HttpSynchronization",
Identifier = "cardinal_directions_textures",
Version = 1
})
local FadeInConstellationLabels = {
Identifier = "os.nightsky.FadeInConstellationLabels",
Name = "Fade In Constellation Labels",
Command = [[openspace.fadeIn("Scene.Constellations.Renderable.Labels",nil)]],
Documentation = "Fades in the constllation labels",
GuiPath = "/Constellations/Lines",
IsLocal = false
}
local FadeOutConstellationLabels = {
Identifier = "os.nightsky.FadeOutConstellationLabels",
Name = "Fade Out Constellation Labels",
Command = [[openspace.fadeOut("Scene.Constellations.Renderable.Labels")]],
Documentation = "Fades out the constellation labels",
GuiPath = "/Constellations/Lines",
IsLocal = false
}
local ShowConstellationElements = {
Identifier = "os.nightsky.ShowConstellationElements",
Name = "Show Constellation Elements",
Command = [[
openspace.setPropertyValueSingle('Scene.Constellations.Renderable.DrawElements', true)
openspace.setPropertyValueSingle('Scene.Constellations.Renderable.Fade', 0)
local fadeSpeed = openspace.propertyValue("OpenSpaceEngine.FadeDuration")
openspace.fadeIn("Scene.Constellations.Renderable", fadeSpeed, "")
]],
Documentation = "Shows the constellation lines with consideration of label state",
GuiPath = "/Constellations/Lines",
IsLocal = false
}
local HideAllMarkings = {
Identifier = "os.nightsky.HideAllMarkings",
Name = "Hide All Markings",
Command = [[
openspace.fadeOut("Scene.Constellations.Renderable")
openspace.fadeOut("{nightsky_marking}")
openspace.fadeOut("{du_grid}")
openspace.fadeOut("{du_grid_labels}")
openspace.fadeOut("{image_constellation}")
]],
Documentation = "Hides all markings in the night sky",
GuiPath = "/Night Sky/Markings",
IsLocal = false
}
local AddTickMarksBand = {
Identifier = "os.nightsky.AddNeswBandMarks",
Name = "Add a band to cardinal directions",
Command = [[
local tex = openspace.propertyValue("Scene.CardinalDirectionSphere.Renderable.Texture")
if (string.find(tex, "small")) then
openspace.setPropertyValueSingle("Scene.CardinalDirectionSphere.Renderable.Texture", "]].. textures:gsub("\\","/") .. [[nesw_lines_red_small.png")
else
openspace.setPropertyValueSingle("Scene.CardinalDirectionSphere.Renderable.Texture", "]].. textures:gsub("\\","/") .. [[nesw_lines_red.png")
end
]],
Documentation = "Adds tick marks to the cardinal directions",
GuiPath = "/Night Sky/Directions",
IsLocal = false
}
local RemoveTickMarksBand = {
Identifier = "os.nightsky.RemoveNeswBandMarks",
Name = "Add a band to cardinal directions",
Command = [[
local tex = openspace.propertyValue("Scene.CardinalDirectionSphere.Renderable.Texture")
if (string.find(tex, "small")) then
openspace.setPropertyValueSingle("Scene.CardinalDirectionSphere.Renderable.Texture", "]].. textures:gsub("\\","/") .. [[nesw_red_small.png")
else
openspace.setPropertyValueSingle("Scene.CardinalDirectionSphere.Renderable.Texture", "]].. textures:gsub("\\","/") .. [[nesw_red.png")
end
]],
Documentation = "Removes tick marks to the cardinal directions",
GuiPath = "/Night Sky/Directions",
IsLocal = false
}
asset.onInitialize(function()
openspace.action.registerAction(FadeInConstellationLabels)
openspace.action.registerAction(FadeOutConstellationLabels)
openspace.action.registerAction(ShowConstellationElements)
openspace.action.registerAction(HideAllMarkings)
openspace.action.registerAction(AddTickMarksBand)
openspace.action.registerAction(RemoveTickMarksBand)
end)
asset.onDeinitialize(function()
openspace.action.removeAction(RemoveTickMarksBand)
openspace.action.removeAction(AddTickMarksBand)
openspace.action.removeAction(HideAllMarkings)
openspace.action.removeAction(ShowConstellationElements)
openspace.action.removeAction(FadeOutConstellationLabels)
openspace.action.removeAction(FadeInConstellationLabels)
end)
asset.export("FadeInConstellationLabels", FadeInConstellationLabels.Identifier)
asset.export("FadeOutConstellationLabels", FadeOutConstellationLabels.Identifier)
asset.export("ShowConstellationElements", ShowConstellationElements.Identifier)
asset.export("HideAllMarkings", HideAllMarkings.Identifier)
asset.export("AddTickMarksBand", AddTickMarksBand.Identifier)
asset.export("RemoveTickMarksBand", RemoveTickMarksBand.Identifier)
@@ -0,0 +1,59 @@
local NorthPole = {
Identifier = "os.nightsky.position.NorthPole",
Name = "Jump to the North Pole",
Command = [[
openspace.navigation.jumpToGeo("Earth", 90.0001, 0.0001, 500)
local script = 'local wait = openspace.propertyValue("NavigationHandler.JumpToFadeDuration")openspace.action.triggerAction("os.nightsky.LookUp");openspace.setPropertyValueSingle("RenderEngine.BlackoutFactor", 1, wait)'
local wait = openspace.propertyValue("NavigationHandler.JumpToFadeDuration")
openspace.scheduleScript(script, wait + 0.1)
]],
Documentation = "",
GuiPath = "/Night Sky/Position",
IsLocal = false
}
local SouthPole = {
Identifier = "os.nightsky.position.SouthPole",
Name = "Jump to the South Pole",
Command = [[
openspace.navigation.jumpToGeo("Earth", -89.9, 0.001, 2800);
local script = 'local wait = openspace.propertyValue("NavigationHandler.JumpToFadeDuration")openspace.action.triggerAction("os.nightsky.LookUp");openspace.setPropertyValueSingle("RenderEngine.BlackoutFactor", 1, wait)'
local wait = openspace.propertyValue("NavigationHandler.JumpToFadeDuration")
openspace.scheduleScript(script, wait + 0.1)
]],
Documentation = "",
GuiPath = "/Night Sky/Position",
IsLocal = false
}
local Equator = {
Identifier = "os.nightsky.position.Equator",
Name = "Jump to the Equator",
Command = [[
local _, long, _ = openspace.globebrowsing.geoPositionForCamera(false);
openspace.navigation.jumpToGeo("Earth", 0.0001, long, 500);
local script = 'local wait = openspace.propertyValue("NavigationHandler.JumpToFadeDuration")openspace.action.triggerAction("os.nightsky.LookUp");openspace.setPropertyValueSingle("RenderEngine.BlackoutFactor", 1, wait)'
local wait = openspace.propertyValue("NavigationHandler.JumpToFadeDuration")
openspace.scheduleScript(script, wait + 0.1)
]],
Documentation = "",
GuiPath = "/Night Sky/Position",
IsLocal = false
}
asset.onInitialize(function()
openspace.action.registerAction(NorthPole)
openspace.action.registerAction(SouthPole)
openspace.action.registerAction(Equator)
end)
asset.onDeinitialize(function()
openspace.action.removeAction(Equator)
openspace.action.removeAction(SouthPole)
openspace.action.removeAction(NorthPole)
end)
asset.export("NorthPole", NorthPole.Identifier)
asset.export("SouthPole", SouthPole.Identifier)
asset.export("Equator", Equator.Identifier)
@@ -0,0 +1,6 @@
asset.require("actions/trails/toggle_all_trails")
asset.require("actions/trails/toggle_trails_planets_moons")
asset.require("actions/planets/planet_lighting")
asset.require("actions/system/undo_event_fades")
asset.require("actions/trails/toggle_all_minor_moon_trails")
asset.require("actions/trails/on_off_all_minor_moons")
+84
View File
@@ -31,14 +31,92 @@ openspace.time.setTime(openspace.time.advancedTime(openspace.time.currentTime(),
IsLocal = false
}
local SiderealWeekIncrease = {
Identifier = "os.time.siderealWeekIncrease",
Name = "Advance 1 sidereal week",
Command = [[
openspace.time.setTime(openspace.time.advancedTime(openspace.time.currentTime(), 86164.0905 * 7));
]],
Documentation = [[Advances time by a sidereal week (Instant)]],
GuiPath = "/Time",
IsLocal = false
}
local SiderealWeekDecrease = {
Identifier = "os.time.siderealWeekDecrease",
Name = "Decrement 1 sidereal week",
Command = [[
openspace.time.setTime(openspace.time.advancedTime(openspace.time.currentTime(), -86164.0905 * 7));
]],
Documentation = [[Decrements time by a sidereal week (Instant)]],
GuiPath = "/Time",
IsLocal = false
}
local SolarDayIncrease = {
Identifier = "os.time.SolarDayIncrease",
Name = "Advance 1 solar day",
Command = [[
openspace.time.setTime(openspace.time.advancedTime(openspace.time.UTC(), "1d"));
]],
Documentation = [[Advances time by a solar day (Instant)]],
GuiPath = "/Time",
IsLocal = false
}
local SolarDayDecrease = {
Identifier = "os.time.SolarDayDecrease",
Name = "Decrement 1 solar day",
Command = [[
openspace.time.setTime(openspace.time.advancedTime(openspace.time.UTC(), "-1d"));
]],
Documentation = [[Decrements time by a solar day (Instant)]],
GuiPath = "/Time",
IsLocal = false
}
local SolarWeekIncrease = {
Identifier = "os.time.SolarWeekIncrease",
Name = "Advance 1 solar week",
Command = [[
openspace.time.setTime(openspace.time.advancedTime(openspace.time.UTC(), "7d"));
]],
Documentation = [[Advances time by a solar week (Instant)]],
GuiPath = "/Time",
IsLocal = false
}
local SolarWeekDecrease = {
Identifier = "os.time.SolarWeekDecrease",
Name = "Decrement 1 solar week",
Command = [[
openspace.time.setTime(openspace.time.advancedTime(openspace.time.UTC(), "-7d"));
]],
Documentation = [[Decrements time by a solar week (Instant)]],
GuiPath = "/Time",
IsLocal = false
}
asset.onInitialize(function()
openspace.action.registerAction(ReverseRate)
openspace.action.registerAction(SiderealDayIncrease)
openspace.action.registerAction(SiderealDayDecrease)
openspace.action.registerAction(SiderealWeekIncrease)
openspace.action.registerAction(SiderealWeekDecrease)
openspace.action.registerAction(SolarDayIncrease)
openspace.action.registerAction(SolarDayDecrease)
openspace.action.registerAction(SolarWeekIncrease)
openspace.action.registerAction(SolarWeekDecrease)
end)
asset.onDeinitialize(function()
openspace.action.removeAction(SolarWeekDecrease)
openspace.action.removeAction(SolarWeekIncrease)
openspace.action.removeAction(SolarDayDecrease)
openspace.action.removeAction(SolarDayIncrease)
openspace.action.removeAction(SiderealWeekDecrease)
openspace.action.removeAction(SiderealWeekIncrease)
openspace.action.removeAction(SiderealDayDecrease)
openspace.action.removeAction(SiderealDayIncrease)
openspace.action.removeAction(ReverseRate)
@@ -47,6 +125,12 @@ end)
asset.export("ReverseRate", ReverseRate.Identifier)
asset.export("SiderealDayIncrease", SiderealDayIncrease.Identifier)
asset.export("SiderealDayDecrease", SiderealDayDecrease.Identifier)
asset.export("SiderealWeekIncrease", SiderealWeekIncrease.Identifier)
asset.export("SiderealWeekDecrease", SiderealWeekDecrease.Identifier)
asset.export("SolarDayIncrease", SolarDayIncrease.Identifier)
asset.export("SolarDayDecrease", SolarDayDecrease.Identifier)
asset.export("SolarWeekIncrease", SolarWeekIncrease.Identifier)
asset.export("SolarWeekDecrease", SolarWeekDecrease.Identifier)
+2 -38
View File
@@ -38,47 +38,11 @@ else
asset.require("scene/solarsystem/planets/default_layers")
end
asset.require("scene/digitaluniverse/2dF")
asset.require("scene/digitaluniverse/2mass")
asset.require("scene/digitaluniverse/6dF")
asset.require("scene/digitaluniverse/abell")
asset.require("scene/digitaluniverse/allsky_hydrogenalpha")
asset.require("scene/digitaluniverse/allsky_visible")
asset.require("scene/digitaluniverse/alternatestarlabels")
asset.require("scene/digitaluniverse/backgroundradiation")
asset.require("scene/digitaluniverse/brown_dwarfs")
asset.require("scene/digitaluniverse/galaxy_clusters")
asset.require("scene/digitaluniverse/constellationbounds")
asset.require("scene/digitaluniverse/constellations")
asset.require("scene/digitaluniverse/exoplanets")
asset.require("scene/digitaluniverse/exoplanets_candidates")
asset.require("scene/digitaluniverse/globularclusters")
asset.require("scene/digitaluniverse/grids")
asset.require("scene/digitaluniverse/galaxy_groups")
asset.require("scene/digitaluniverse/h2regions")
asset.require("scene/digitaluniverse/local_group_dwarfs")
asset.require("scene/digitaluniverse/milkyway")
asset.require("scene/digitaluniverse/milkyway_arm_labels")
asset.require("scene/digitaluniverse/milkyway_label")
asset.require("scene/digitaluniverse/obassociations")
asset.require("scene/digitaluniverse/oort_cloud")
asset.require("scene/digitaluniverse/openclusters")
asset.require("scene/digitaluniverse/planetarynebulae")
asset.require("scene/digitaluniverse/pulsars")
asset.require("scene/digitaluniverse/quasars")
asset.require("scene/digitaluniverse/star_uncertainty")
asset.require("scene/digitaluniverse/starlabels")
asset.require("scene/digitaluniverse/starorbits")
asset.require("scene/digitaluniverse/stars")
asset.require("scene/digitaluniverse/superclusters")
asset.require("scene/digitaluniverse/supernovaremnants")
asset.require("scene/digitaluniverse/tully")
asset.require("scene/digitaluniverse/voids")
asset.require("scene/digitaluniverse/white_dwarfs")
asset.require("scene/digitaluniverse/digitaluniverse")
asset.require("nightsky/nightsky")
asset.require("customization/globebrowsing")
asset.require("actions/default_actions")
asset.require("actions/solarsystem_actions")
asset.require("modules/exoplanets/exoplanets")
asset.require("modules/skybrowser/skybrowser")
+9 -6
View File
@@ -4,11 +4,10 @@
asset.require("spice/core")
asset.require("dashboard/default_dashboard")
-- Load default key bindings applicable to most scenes
asset.require("./default_keybindings")
-- Load web gui
local webGui = asset.require("util/webgui")
-- Load default actions and key bindings applicable to most scenes
asset.require("actions/default_actions")
asset.require("./default_keybindings")
-- Scale the different UI components based on the operating system's DPI scaling value
asset.require("util/dpiscaling")
@@ -19,8 +18,12 @@ asset.require("util/launcher_images")
-- Modules and component settings
asset.require("modules/touch/default_settings")
-- Load web gui
local webGui = asset.require("util/webgui")
asset.onInitialize(function()
webGui.setCefRoute("onscreen")
openspace.setPropertyValueSingle("RenderEngine.VerticalLogOffset", 0.100000)
openspace.setPropertyValueSingle("RenderEngine.VerticalLogOffset", 0.1)
openspace.setPropertyValueSingle("Dashboard.StartPositionOffset", { 15.0, 49.0 })
openspace.setPropertyValueSingle("RenderEngine.ShowCamera", false)
end)
+49 -321
View File
@@ -1,348 +1,76 @@
local propertyHelper = asset.require("util/property_helper")
local ToggleNativeUi = {
Identifier = "os.ToggleNativeUi",
Name = "Show native GUI",
Command = propertyHelper.invert("Modules.ImGUI.Enabled"),
Documentation = "Shows or hides the native UI",
GuiPath = "/System/GUI",
IsLocal = true
}
local ToggleShutdown = {
Identifier = "os.ToggleShutdown",
Name = "Toggle shutdown",
Command = "openspace.toggleShutdown()",
Documentation = [[
Toggles the shutdown that will stop OpenSpace after a grace period. Press again to
cancel the shutdown during this period]],
GuiPath = "/System",
IsLocal = true
}
local TakeScreenshot = {
Identifier = "os.TakeScreenshot",
Name = "Take screenshot",
Command = "openspace.takeScreenshot()",
Documentation = [[Saves the contents of the screen to a file in the ${SCREENSHOTS}
directory]],
GuiPath = "/System/Rendering",
IsLocal = true
}
local TogglePauseInterpolated = {
Identifier = "os.TogglePauseInterpolated",
Name = "Toggle pause (interpolate)",
Command = "openspace.time.pauseToggleViaKeyboard()",
Documentation = "Smoothly starts and stops the simulation time",
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local TogglePauseImmediate = {
Identifier = "os.TogglePauseImmediate",
Name = "Toggle pause (immediate)",
Command = "openspace.time.togglePause()",
Documentation = "Immediately starts and stops the simulation time",
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local ToggleRotationFriction = {
Identifier = "os.ToggleRotationFriction",
Name = "Toggle rotation friction",
Command = propertyHelper.invert("NavigationHandler.OrbitalNavigator.Friction.RotationalFriction"),
Documentation = [[Toggles the rotational friction of the camera. If it is disabled, the
camera rotates around the focus object indefinitely]],
GuiPath = "/Navigation",
IsLocal = true
}
local ToggleZoomFriction = {
Identifier = "os.ToggleZoomFriction",
Name = "Toggle zoom friction",
Command = propertyHelper.invert("NavigationHandler.OrbitalNavigator.Friction.ZoomFriction"),
Documentation = [[Toggles the zoom friction of the camera. If it is disabled, the camera
rises up from or closes in towards the focus object indefinitely]],
GuiPath = "/Navigation",
IsLocal = true
}
local ToggleRollFriction = {
Identifier = "os.ToggleRollFriction",
Name = "Toggle roll friction",
Command = propertyHelper.invert("NavigationHandler.OrbitalNavigator.Friction.RollFriction"),
Documentation = [[Toggles the roll friction of the camera. If it is disabled, the camera
rolls around its own axis indefinitely]],
GuiPath = "/Navigation",
IsLocal = true
}
local FadeToBlack = {
Identifier = "os.FadeToBlack",
Name = "Fade to/from black",
Command = [[
if openspace.propertyValue("RenderEngine.BlackoutFactor") > 0.5 then
openspace.setPropertyValueSingle("RenderEngine.BlackoutFactor", 0.0, 3)
else
openspace.setPropertyValueSingle("RenderEngine.BlackoutFactor", 1.0, 3)
end
]],
Documentation = [[Toggles the fade to black within 3 seconds or shows the rendering
after 3 seconds]],
GuiPath = "/Rendering",
IsLocal = false
}
local ToggleMainGui = {
Identifier = "os.ToggleMainGui",
Name = "Toggle main GUI",
Command = propertyHelper.invert("Modules.CefWebGui.Visible"),
Documentation = "Toggles the main GUI",
GuiPath = "/System/GUI",
IsLocal = true
}
local ToggleOverlays = {
Identifier = "os.ToggleOverlays",
Name = "Toggle dashboard and overlays",
Command = [[
local isEnabled = openspace.propertyValue("Dashboard.IsEnabled")
openspace.setPropertyValueSingle("Dashboard.IsEnabled", not isEnabled)
openspace.setPropertyValueSingle("RenderEngine.ShowLog", not isEnabled)
openspace.setPropertyValueSingle("RenderEngine.ShowVersion", not isEnabled)
openspace.setPropertyValueSingle("RenderEngine.ShowCamera", not isEnabled)
]],
Documentation = "Toggles the dashboard and overlays",
GuiPath = "/System/GUI",
IsLocal = true
}
local ToggleMasterRendering = {
Identifier = "os.ToggleMasterRendering",
Name = "Toggle rendering on master",
Command = propertyHelper.invert("RenderEngine.DisableMasterRendering"),
Documentation = "Toggles the rendering on master",
GuiPath = "/System/Rendering",
IsLocal = true
}
local NextDeltaStepInterpolate = {
Identifier = "os.NextDeltaStepInterpolate",
Name = "Next simulation time step (interpolate)",
Command = "openspace.time.interpolateNextDeltaTimeStep()",
Documentation = [[Smoothly interpolates the simulation speed to the next simulation time
step, if one exists]],
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local NextDeltaStepImmediate = {
Identifier = "os.NextDeltaStepImmediate",
Name = "Next simulation time step (immediate)",
Command = "openspace.time.setNextDeltaTimeStep()",
Documentation = [[Immediately set the simulation speed to the next simulation time step,
if one exists]],
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local PreviousDeltaStepInterpolate = {
Identifier = "os.PreviousDeltaStepInterpolate",
Name = "Previous simulation time step (interpolate)",
Command = "openspace.time.interpolatePreviousDeltaTimeStep()",
Documentation = [[Smoothly interpolates the simulation speed to the previous simulation
time step, if one exists]],
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local PreviousDeltaStepImmediate = {
Identifier = "os.PreviousDeltaStepImmediate",
Name = "Previous simulation time step (immediate)",
Command = "openspace.time.setPreviousDeltaTimeStep()",
Documentation = [[Immediately set the simulation speed to the previous simulation time
step, if one exists]],
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local RealTimeDeltaStepInterpolate = {
Identifier = "os.RealTimeDeltaStepInterpolate",
Name = "Reset the simulation time to realtime (interpolate)",
Command = "openspace.time.interpolateDeltaTime(1)",
Documentation = "Smoothly interpolate the simulation speed to match real-time speed",
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local RealTimeDeltaStepImmediate = {
Identifier = "os.RealTimeDeltaStepImmediate",
Name = "Reset the simulation time to realtime (immediate)",
Command = "openspace.time.setDeltaTime(1)",
Documentation = "Immediately set the simulation speed to match real-time speed",
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local DateToNowInterpolate = {
Identifier = "os.DateToNowInterpolate",
Name = "Set the in-game time to now (interpolate)",
Command = "openspace.time.interpolateTime(openspace.time.currentWallTime())",
Documentation = "Immediately set the current in-game time to the 'now' time",
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local DateToNowImmediate = {
Identifier = "os.DateToNowImmediate",
Name = "Set the in-game time to now (immediate)",
Command = "openspace.time.setTime(openspace.time.currentWallTime())",
Documentation = "Smoothly interpolate the current in-game time to the 'now' time",
GuiPath = "/Time/Simulation Speed",
IsLocal = true
}
local ReloadGui = {
Identifier = "os.ReloadGui",
Name = "Reload GUI",
Command = [[openspace.setPropertyValueSingle("Modules.CefWebGui.Reload", nil)]],
Documentation = "Reloads the GUI",
GuiPath = "/System/GUI",
IsLocal = true
}
local actions = asset.require("actions/default_actions")
asset.onInitialize(function()
openspace.action.registerAction(ToggleNativeUi)
openspace.bindKey("F1", ToggleNativeUi.Identifier)
openspace.bindKey("Ctrl+Q", actions.ToggleShutdown)
openspace.action.registerAction(ToggleShutdown)
openspace.bindKey("ESC", ToggleShutdown.Identifier)
openspace.bindKey("F12", actions.TakeScreenshot)
openspace.bindKey("PRINT_SCREEN", actions.TakeScreenshot)
openspace.action.registerAction(TakeScreenshot)
openspace.bindKey("F12", TakeScreenshot.Identifier)
openspace.bindKey("PRINT_SCREEN", TakeScreenshot.Identifier)
openspace.bindKey("SPACE", actions.TogglePauseInterpolated)
openspace.bindKey("Shift+SPACE", actions.TogglePauseImmediate)
openspace.action.registerAction(TogglePauseInterpolated)
openspace.bindKey("SPACE", TogglePauseInterpolated.Identifier)
openspace.bindKey("F", actions.ToggleRotationFriction)
openspace.bindKey("Shift+F", actions.ToggleZoomFriction)
openspace.bindKey("Ctrl+F", actions.ToggleRollFriction)
openspace.action.registerAction(TogglePauseImmediate)
openspace.bindKey("Shift+SPACE", TogglePauseImmediate.Identifier)
openspace.bindKey("B", actions.FadeToBlack)
openspace.action.registerAction(ToggleRotationFriction)
openspace.bindKey("F", ToggleRotationFriction.Identifier)
openspace.bindKey("F1", actions.ToggleMainGui)
openspace.bindKey("Shift+F1", actions.ToggleOverlays)
openspace.action.registerAction(ToggleZoomFriction)
openspace.bindKey("Shift+F", ToggleZoomFriction.Identifier)
openspace.bindKey("F2", actions.ToggleNativeUi)
openspace.action.registerAction(ToggleRollFriction)
openspace.bindKey("Ctrl+F", ToggleRollFriction.Identifier)
openspace.bindKey("Right", actions.NextDeltaStepInterpolate)
openspace.bindKey("Shift+Right", actions.NextDeltaStepImmediate)
openspace.action.registerAction(FadeToBlack)
openspace.bindKey("B", FadeToBlack.Identifier)
openspace.bindKey("Left", actions.PreviousDeltaStepInterpolate)
openspace.bindKey("Shift+Left", actions.PreviousDeltaStepImmediate)
openspace.action.registerAction(ToggleMainGui)
openspace.bindKey("TAB", ToggleMainGui.Identifier)
openspace.bindKey("Down", actions.RealTimeDeltaStepInterpolate)
openspace.bindKey("Shift+Down", actions.RealTimeDeltaStepImmediate)
openspace.action.registerAction(ToggleOverlays)
openspace.bindKey("Shift+TAB", ToggleOverlays.Identifier)
openspace.action.registerAction(ToggleMasterRendering)
openspace.bindKey("Alt+R", ToggleMasterRendering.Identifier)
openspace.action.registerAction(NextDeltaStepInterpolate)
openspace.bindKey("Right", NextDeltaStepInterpolate.Identifier)
openspace.action.registerAction(NextDeltaStepImmediate)
openspace.bindKey("Shift+Right", NextDeltaStepImmediate.Identifier)
openspace.action.registerAction(PreviousDeltaStepInterpolate)
openspace.bindKey("Left", PreviousDeltaStepInterpolate.Identifier)
openspace.action.registerAction(PreviousDeltaStepImmediate)
openspace.bindKey("Shift+Left", PreviousDeltaStepImmediate.Identifier)
openspace.action.registerAction(RealTimeDeltaStepInterpolate)
openspace.bindKey("Down", RealTimeDeltaStepInterpolate.Identifier)
openspace.action.registerAction(RealTimeDeltaStepImmediate)
openspace.bindKey("Shift+Down", RealTimeDeltaStepImmediate.Identifier)
openspace.action.registerAction(DateToNowInterpolate)
openspace.bindKey("Up", DateToNowInterpolate.Identifier)
openspace.action.registerAction(DateToNowImmediate)
openspace.bindKey("Shift+Up", DateToNowImmediate.Identifier)
openspace.action.registerAction(ReloadGui)
openspace.bindKey("F5", ReloadGui.Identifier)
openspace.bindKey("F5", actions.ReloadGui)
end)
asset.onDeinitialize(function()
openspace.clearKey("F5")
openspace.action.removeAction(ReloadGui)
openspace.clearKey("F5") -- actions.ReloadGui
openspace.clearKey("Shift+Up")
openspace.action.removeAction(DateToNowImmediate)
openspace.clearKey("Shift+Down") -- actions.RealTimeDeltaStepImmediate
openspace.clearKey("Down") -- actions.RealTimeDeltaStepInterpolate
openspace.clearKey("Up")
openspace.action.removeAction(DateToNowInterpolate)
openspace.clearKey("Shift+Left") -- actions.PreviousDeltaStepImmediate
openspace.clearKey("Left") -- actions.PreviousDeltaStepInterpolate
openspace.clearKey("Shift+Down")
openspace.action.removeAction(RealTimeDeltaStepImmediate)
openspace.clearKey("Shift+Right") -- actions.NextDeltaStepImmediate
openspace.clearKey("Right") -- actions.NextDeltaStepInterpolate
openspace.clearKey("Down")
openspace.action.removeAction(RealTimeDeltaStepInterpolate)
openspace.clearKey("F2") -- actions.ToggleNativeUi
openspace.clearKey("Shift+Left")
openspace.action.removeAction(PreviousDeltaStepImmediate)
openspace.clearKey("Shift+F1") -- actions.ToggleOverlays
openspace.clearKey("F1") -- actions.ToggleMainGui
openspace.clearKey("Left")
openspace.action.removeAction(PreviousDeltaStepInterpolate)
openspace.clearKey("B") -- actions.FadeToBlack
openspace.clearKey("Shift+Right")
openspace.action.removeAction(NextDeltaStepImmediate)
openspace.clearKey("Ctrl+F") -- actions.ToggleRollFriction
openspace.clearKey("Shift+F") -- actions.ToggleZoomFriction
openspace.clearKey("F") -- actions.ToggleRotationFriction
openspace.clearKey("Right")
openspace.action.removeAction(NextDeltaStepInterpolate)
openspace.clearKey("Shift+SPACE") -- actions.TogglePauseImmediate
openspace.clearKey("SPACE") -- actions.TogglePauseInterpolated
openspace.clearKey("Alt+R")
openspace.action.removeAction(ToggleMasterRendering)
openspace.clearKey("F12") -- actions.TakeScreenshot
openspace.clearKey("PRINT_SCREEN") -- actions.TakeScreenshot
openspace.clearKey("Shift+TAB")
openspace.action.removeAction(ToggleOverlays)
openspace.clearKey("TAB")
openspace.action.removeAction(ToggleMainGui)
openspace.clearKey("B")
openspace.action.removeAction(FadeToBlack)
openspace.clearKey("Ctrl+F")
openspace.action.removeAction(ToggleRollFriction)
openspace.clearKey("Shift+F")
openspace.action.removeAction(ToggleZoomFriction)
openspace.clearKey("F")
openspace.action.removeAction(ToggleRotationFriction)
openspace.clearKey("Shift+SPACE")
openspace.action.removeAction(TogglePauseImmediate)
openspace.clearKey("SPACE")
openspace.action.removeAction(TogglePauseInterpolated)
openspace.clearKey("F12")
openspace.clearKey("PRINT_SCREEN")
openspace.action.removeAction(TakeScreenshot)
openspace.clearKey("ESC")
openspace.action.removeAction(ToggleShutdown)
openspace.clearKey("F1")
openspace.action.removeAction(ToggleNativeUi)
openspace.clearKey("Ctrl+Q") -- actions.ToggleShutdown
end)
asset.meta = {
Name = "Default Keybindings",
Description ="Asset with default key bindings that are useful for all profiles",
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license"
}
@@ -0,0 +1,9 @@
{
"data": [
[ "2024-05-10T00:00:00Z", 2.33 ],
[ "2024-05-10T03:00:00Z", 3 ],
[ "2024-05-10T06:00:00Z", 3 ],
[ "2024-05-10T09:00:00Z", 2.67 ],
[ "2024-05-10T12:00:00Z", 2.33 ]
]
}
@@ -0,0 +1,10 @@
{
"data": [
[ "2024-05-10T00:00:00Z", 2.33 ],
[ "2024-05-10T03:00:00Z", true ],
[ "2024-05-10T06:00:00Z", "Test string" ],
[ "2024-05-10T09:00:00Z", { "a": 1.0, "b": 2.0 } ],
[ "2024-05-10T12:00:00Z", [ 1.0, 2.0, 3.0 ] ],
[ "2024-05-10T15:00:00Z", 3 ]
]
}
@@ -0,0 +1,16 @@
-- Basic
-- This example shows how to create a time-varying text dashboard item.
local Item = {
Type = "DashboardItemTimeVaryingText",
Identifier = "DashboardItemTimeVaryingText_Example",
DataFile = asset.resource("data/dummydata.json"),
}
asset.onInitialize(function()
openspace.dashboard.addDashboardItem(Item)
end)
asset.onDeinitialize(function()
openspace.dashboard.removeDashboardItem(Item)
end)
@@ -0,0 +1,17 @@
-- Mixed
-- This example shows how to create a time-varying text dashboard item that is using a
-- mixed type of data entries in the `DataFile`.
local Item = {
Type = "DashboardItemTimeVaryingText",
Identifier = "DashboardItemTimeVaryingText_Example_Mixed",
DataFile = asset.resource("data/dummydata_mixed.json"),
}
asset.onInitialize(function()
openspace.dashboard.addDashboardItem(Item)
end)
asset.onDeinitialize(function()
openspace.dashboard.removeDashboardItem(Item)
end)
@@ -0,0 +1,19 @@
-- Styled
-- This example shows how to create a time-varying text dashboard item.
-- It has a custom font size and text before the time varying text.
local Item = {
Type = "DashboardItemTimeVaryingText",
Identifier = "DashboardItemTimeVaryingText_Example_Styled",
DataFile = asset.resource("data/dummydata.json"),
FormatString = "Observed KP index: {}",
FontSize = 40
}
asset.onInitialize(function()
openspace.dashboard.addDashboardItem(Item)
end)
asset.onDeinitialize(function()
openspace.dashboard.removeDashboardItem(Item)
end)
@@ -0,0 +1,34 @@
-- Scale by Distance to Camera
-- This example creates a textured plane that is scaled based on the distance to the
-- camera, so that it stays a constant size in screen space. The scale is limited so that
-- the plane does not become larger or smaller than a given max height and min height, in
-- meters.
local earth = asset.require("scene/solarsystem/planets/earth/earth")
local Node = {
Identifier = "RenderablePlaneImageLocal_Example_ScaleByDistance",
Renderable = {
Type = "RenderablePlaneImageLocal",
Size = 100000,
Texture = openspace.absPath("${DATA}/test2.jpg"),
DistanceScalingSettings = {
ScaleByDistance = true,
ApparentSizeMultiplier = 0.01,
ScaleByDistanceMaxHeight = 200000,
ScaleByDistanceMinHeight = 30000
}
},
GUI = {
Name = "RenderablePlaneImageLocal - ScaleByDistance",
Path = "/Examples"
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(Node)
end)
@@ -15,7 +15,7 @@ local Node = {
File = asset.resource("data/dummydata.csv"),
-- Change the orientation render option to face the camera position instead
-- of its view direction
OrientationRenderOption = "Camera Position Normal",
Billboard = "Camera Position Normal",
-- Add a texture so we can more easily see how the orientation is changed
Texture = {
File = openspace.absPath("${DATA}/test3.jpg")
@@ -0,0 +1,30 @@
-- Only Far Renderable
-- This example uses only shows a textured plane when the camera is further than the
-- specified distance from the object and shows nothing if the camera is closer than that
-- distance
local Node = {
Identifier = "RenderableSwitch_Example-Far",
Renderable = {
Type = "RenderableSwitch",
RenderableFar = {
Type = "RenderablePlaneImageLocal",
Size = 300000000000,
Texture = openspace.absPath("${DATA}/test.jpg")
},
DistanceThreshold = 3000000000000
},
GUI = {
Name = "RenderableSwitch - Far",
Path = "/Examples"
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(Node)
end)
@@ -0,0 +1,29 @@
-- Only Near Renderable
-- This example uses only shows a textured plane when the camera is within the specified
-- distance from the object and shows nothing if the camera is further away.
local Node = {
Identifier = "RenderableSwitch_Example-Near",
Renderable = {
Type = "RenderableSwitch",
RenderableNear = {
Type = "RenderablePlaneImageLocal",
Size = 300000000000,
Texture = openspace.absPath("${DATA}/test.jpg")
},
DistanceThreshold = 2000000000000
},
GUI = {
Name = "RenderableSwitch - Near",
Path = "/Examples"
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(Node)
end)
@@ -0,0 +1,36 @@
-- Basic
-- This example shows how to create a renderable that switches between two textured planes
-- in 3D space, where one texture is loaded from a local file on disk and the other is
-- loaded from the internet though a web URL.
-- The switch is done based on the distance from the camera to the renderable.
local Node = {
Identifier = "RenderableSwitch_Example",
Renderable = {
Type = "RenderableSwitch",
RenderableNear = {
Type = "RenderablePlaneImageLocal",
Size = 300000000000,
Texture = openspace.absPath("${DATA}/test.jpg")
},
RenderableFar = {
Type = "RenderablePlaneImageOnline",
Size = 300000000000,
URL = "http://data.openspaceproject.com/examples/renderableplaneimageonline.jpg"
},
DistanceThreshold = 2000000000000
},
GUI = {
Name = "RenderableSwitch - Basic",
Path = "/Examples"
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(Node)
end)
@@ -0,0 +1,23 @@
-- Basic
-- Creates a screenspace image plane with controls to for a blackout shape. Can be used
-- when using a secondary projector to project content on a dome surface.
local inset = {
Identifier = "ScreenSpaceInsetBlackout_Example",
Type = "ScreenSpaceInsetBlackout",
Name = "ScreenSpaceInsetBlackout Example - Basic",
Blackoutshape = {
-- Must always contain four corners in the following order:
-- top-left, top-right, bottom-right, bottom-left
Corners = { {0.0, 1.0}, {1.0, 1.0}, {1.0, 0.0}, {0.0, 0.0} }
},
Scale = 1.0
}
asset.onInitialize(function()
openspace.addScreenSpaceRenderable(inset)
end)
asset.onDeinitialize(function()
openspace.removeScreenSpaceRenderable(inset)
end)
@@ -0,0 +1,32 @@
-- Calibration Pattern
-- Creates a screenspace image plane with controls to for a blackout shape. Can be used
-- when using a secondary projector to project content on a dome surface.
local texturePath = asset.resource({
Type = "HttpSynchronization",
Identifier = "calibration_pattern",
Name = "ScreenSpaceInsetBlackout Calibration Pattern",
Version = 1
})
local inset = {
Identifier = "ScreenSpaceInsetBlackout_Example_Calibration_Pattern",
Type = "ScreenSpaceInsetBlackout",
Name = "ScreenSpaceInsetBlackout Example - Calibration Pattern",
Blackoutshape = {
-- Must always contain four corners in the following order:
-- top-left, top-right, bottom-right, bottom-left
Corners = { {0.0, 1.0}, {1.0, 1.0}, {1.0, 0.0}, {0.0, 0.0} },
CalibrationTexturePath = texturePath .. "calibration-pattern.png";
},
Scale = 1.0
}
asset.onInitialize(function()
openspace.addScreenSpaceRenderable(inset)
end)
asset.onDeinitialize(function()
openspace.removeScreenSpaceRenderable(inset)
end)
@@ -0,0 +1,35 @@
-- Points
-- Creates a screenspace image plane with controls to for a blackout shape. Can be used
-- when using a secondary projector to project content on a dome surface.
local inset = {
Identifier = "ScreenSpaceInsetBlackout_Example_Points",
Type = "ScreenSpaceInsetBlackout",
Name = "ScreenSpaceInsetBlackout Example - Points",
Blackoutshape = {
-- Must always contain four corners in the following order:
-- top-left, top-right, bottom-right, bottom-left
Corners = { {0.0, 0.9}, {1.0, 0.9}, {0.9, 0.1}, {0.1, 0.1} },
-- Contains control points for top spline in order left to right
Top = { {0.5, 1.0} },
-- Contains control points for right spline in order top to bottom
Right = { },
-- Contains control points for bottom spline in order right to left
Bottom = { {0.7, 0.2}, {0.3, 0.2} },
-- Contains control points for left spline in order bottom to top
Left = { }
},
Scale = 1.0
}
asset.onInitialize(function()
openspace.addScreenSpaceRenderable(inset)
end)
asset.onDeinitialize(function()
openspace.removeScreenSpaceRenderable(inset)
end)
@@ -0,0 +1,16 @@
{
"files": [
{
"timestamp": "2024-05-10 15:00:00.000",
"url": "http://data.openspaceproject.com/examples/renderableplaneimageonline.jpg"
},
{
"timestamp": "2024-05-10 15:10:00.000",
"url": "https://data.openspaceproject.com/examples/renderableplaneimageonline_2.jpg"
},
{
"timestamp": "2024-05-10 15:20:00.000",
"url": "http://data.openspaceproject.com/examples/renderableplaneimageonline.jpg"
}
]
}
@@ -0,0 +1,18 @@
-- Basic
-- Create a time-varying screenspace image plane that shows the content of images from
-- web URLs based on in-game simulation time. The data in this example has images shown at
-- 2024-05-10 between 15:00:00 and 15:20:00.
local Item = {
Type = "ScreenSpaceTimeVaryingImageOnline",
Identifier = "ScreenSpaceTimeVaryingImageOnline_Example",
FilePath = asset.resource("data/example.json")
}
asset.onInitialize(function()
openspace.addScreenSpaceRenderable(Item)
end)
asset.onDeinitialize(function()
openspace.removeScreenSpaceRenderable(Item)
end)
@@ -0,0 +1,21 @@
-- Nodes sonification
-- This example adds the ISS and Tiangong space stations to the NodesTelemetry in the
-- Telemetry module. This should be used together with the nodesSonification.scd file in
-- SuperCollider to listen to an example sonification of the nodes.
--
-- This is a good foundation for creating your own sonification of any node(s) in
-- OpenSpace. If you want to use this to create your own sonification, you can copy this
-- file and the nodesSonification.scd file to your own asset folder and modify them to
-- your liking. In this file, that modification would be to replace the ISS and Tiangong
-- identifies with the identifiers of the node(s) you want to sonify instead.
--
-- For more information about sonification in OpenSpace and how to use it, see the
-- documentation:
-- https://docs.openspaceproject.com/latest/creating-data-assets/modules/telemetry/sonification.html
asset.require("scene/solarsystem/planets/earth/satellites/misc/iss")
asset.require("scene/solarsystem/planets/earth/satellites/misc/tiangong")
asset.onInitialize(function ()
openspace.telemetry.addNodes({ "ISS", "Tiangong" })
end)
@@ -0,0 +1,21 @@
-- Voyager sonification
-- This example adds the Voyager 1 and Voyager 2 probes to the NodesTelemetry in the
-- Telemetry module. This should be used together with the voyager-sonification.scd file
-- in SuperCollider to listen to an example sonification of the Voyager probes.
--
-- This is a good foundation for creating your own sonification of any node(s) in
-- OpenSpace. If you want to use this to create your own sonification, you can copy this
-- file and the voyager-sonification.scd file to your own asset folder and modify them to
-- your liking. In this file, that modification would be to replace the Voyager 1 and 2
-- identifiers with the identifiers of the node(s) you want to sonify instead.
--
-- For more information about sonification in OpenSpace and how to use it, see the
-- documentation:
-- https://docs.openspaceproject.com/latest/creating-data-assets/modules/telemetry/sonification.html
asset.require("scene/solarsystem/missions/voyager/voyager1")
asset.require("scene/solarsystem/missions/voyager/voyager2")
asset.onInitialize(function ()
openspace.telemetry.addNodes({ "Voyager_1", "Voyager_2" })
end)
@@ -0,0 +1,438 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2025 *
* *
* 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. *
****************************************************************************************/
Platform.userExtensionDir
NetAddr.langPort;
NetAddr.localAddr;
/*****************************************************************************************
* This is a SuperCollider file that needs to be run in the SuperCollider application *
* that can be downloaded here: https://supercollider.github.io/ *
* *
* This is an example file that shows all the messages that the Telemetry module in *
* OpenSpace can send over Open Sound Control (OSC). SuperCollider can then listen to *
* these OSC messages and create sounds based on their content (a sonification). This *
* example only listens to the messages and displays their content in the log to the *
* right in the SuperCollider application. For a more extensive example that shows how *
* to create sounds in SuperCollider based on the data from OpenSpace, see the *
* planets-sonification.scd file located in data\assets\modules\telemetry\sonification. *
* *
* To run a SuperCollider file, click any line within the parentheses below, such as the *
* marked line. When you have selected a line, press the CTRL and ENTER keys on your *
* keyboard at the same time, and SuperCollider will run the code. You will see a *
* message appear in the log to the right, the message should be: *
* "-> OSCdef(Neptune, /Neptune, nil, nil, nil)". At this point, SuperCollider is ready *
* to receive messages from OpenSpace. For a guide on how to enable and use the *
* Telemetry module inside OpenSpace, see this documentation page: *
* https://docs.openspaceproject.com/latest/creating-data-assets/modules/telemetry/ *
* index.html *
****************************************************************************************/
(
// To run this example, click this line and press CTRL + ENTER on the keyboard
// When finished, press CTRL + . on you keyboard simultaneously to stop the sonification
// Camera sonification
OSCdef.new(
\Camera,
{
arg msg;
// msg[0] = OSC Label.
// msg[1] = The x position of the camera in the world.
// msg[2] = The y position of the camera in the world.
// msg[3] = The z position of the camera in the world.
// msg[4] = The w component of the quaternion rotation of the camera.
// msg[5] = The x component of the quaternion rotation of the camera.
// msg[6] = The y component of the quaternion rotation of the camera.
// msg[7] = The z component of the quaternion rotation of the camera.
// msg[8] = The movement speed of the camera, in the distance unit per second
// specified by the next item.
// msg[9] = The distance unit for the movement speed of the camera, as a string in
// singular form with the first letter capitalized. For example,
// "Kilometer".
//
// Note that the first seven items describe the position and orientation of the
// camera. The first three items specify the x, y, and z positions of the camera
// in the world, in relation to the solar system barycenter. The next four items
// are the quaternion rotation of the camera in the order of w, x, y, and z.
("Camera: " + msg).postln;
},
'/Camera'
);
// Focus sonification
OSCdef.new(
\Focus,
{
arg msg;
// msg[0] = OSC Label.
// msg[1] = The identifier of the new focus in OpenSpace, as a string.
("Focus: " + msg).postln;
},
'/Focus'
);
// Surround mode sonification
OSCdef.new(
\Mode,
{
arg msg;
// msg[0] = OSC Label.
// msg[1] = The first item is an integer value that specifies what method was
// used to calculate the angles. If the value is 0, then the method
// used was the Horizontal angle calculation mode. In the case where
// the value is 1, then the Circular angle calculation mode was used.
// msg[2] = The second value is an integer value of either 0 or 1 that
// determines if the additional elevation angle is used or not. If the
// value is 1, the additional elevation angle is calculated. Otherwise,
// if 0, the elevation angle is always set to 0.0.
("Mode: " + msg).postln;
},
'/Mode'
);
// Time sonification
OSCdef.new(
\Time,
{
arg msg;
// msg[0] = OSC Label.
// msg[1] = The speed of the simulation time, specified in the selected time unit
// in the simulation, per real-life second. For example, 10 simulated
// seconds per real-life second means that the simulation goes 10 times
// faster than real-life.
// msg[2] = The selected time unit for the speed of simulation time, as a string
// in singular form with the first letter capitalized. For example,
// "Day".
// msg[3] = The current simulation time in OpenSpace specified in J2000 seconds,
// that is, the number of seconds past the J2000 epoch
// (i.e. January 1, 2000 12:00:00 TT).
("Time: " + msg).postln;
},
'/Time'
);
// Nodes sonification, data map:
// msg[0] = OSC Label (The identifier for each node).
// msg[1] = The distance from the camera to the node, in the distance unit specified in
// the last item.
// msg[2] = The horizontal angle to the node, in radians, with the current angle
// calculation mode taken into account. For more information, see
// https://docs.openspaceproject.com/latest/creating-data-assets/modules/
// telemetry/angle-information.html.
// msg[3] = The elevation angle to the node, in radians, with the current angle
// calculation mode taken into account. Again, see
// https://docs.openspaceproject.com/latest/creating-data-assets/modules/
// telemetry/angle-information.html for details.
// msg[4] = The unit for the distance to the camera, as a string in singular form with
// the first letter capitalized. For example, "Meter".
// ISS node
OSCdef.new(
\ISS,
{
arg msg;
// Follow the nodes sonification data map above
("ISS: " + msg).postln;
},
'/ISS'
);
// Tiangong node
OSCdef.new(
\Tiangong,
{
arg msg;
// Follow the nodes sonification data map above
("Tiangong: " + msg).postln;
},
'/Tiangong'
);
// Planet related sonifications:
// Compare planets
OSCdef.new(
\Compare,
{
arg msg;
// msg[0] = OSC Label.
// msg[1] = The index of the first planet to be compared. See the list below on
// how to convert the index to a planet name:
// 0 -> None selected
// 1 -> Mercury
// 2 -> Venus
// 3 -> Earth
// 4 -> Mars
// 5 -> Jupiter
// 6 -> Saturn
// 7 -> Uranus
// 8 -> Neptune
// msg[2] = The index of the second planet to be compared (will never be the same
// as the first).
// msg[3] = List of user interface settings for the comparison, which determines
// which aspects of the sonification should be turned on or off. A value
// of 0 means that a setting is turned off, and 1 means that it is turned
// on. The order of the settings can be seen in the list below:
// msg[3][0] = Size/day. 1 -> Size/day is turned on.
// 0 -> Size/day is turned off.
// msg[3][1] = Gravity
// msg[3][2] = Temperature
// msg[3][3] = Atmosphere
// msg[3][4] = Moons
// msg[3][5] = Rings
("Compare: " + msg).postln;
},
'/Compare'
);
// Planets overview
OSCdef.new(
\Overview,
{
arg msg;
// msg[0] = OSC Label.
// msg[1] = List of user interface settings for the planets overview. This
// determines which planets are part of the sonification or not. A value
// of 0 means that the planet is turned off, and a 1 means that it is
// turned on. The order of the settings can be seen in the list below:
// msg[1][0] = Mercury. 1 -> Mercury is turned on.
// 0 -> Mercury is turned off.
// msg[1][1] = Venus
// msg[1][2] = Earth
// msg[1][3] = Mars
// msg[1][4] = Jupiter
// msg[1][5] = Saturn
// msg[1][6] = Uranus
// msg[1][7] = Neptune
("Overview: " + msg).postln;
},
'/Overview'
);
// Planets sonifications, data map:
// msg[0] = OSC Label (The name of the planet).
// msg[1] = The distance from the camera to the planet in kilometers.
// msg[2] = The horizontal angle in radians to the planet, with the current angle
// calculation mode taken into account. For more information see
// https://docs.openspaceproject.com/latest/creating-data-assets/modules/
// telemetry/angle-information.html.
// msg[3] = The elevation angle in radians to the planet, with the current angle
// calculation mode taken into account. Again, see
// https://docs.openspaceproject.com/latest/creating-data-assets/modules/
// telemetry/angle-information.html for details.
// msg[4] = List of user interface settings for the planet sonification, which aspects
// of the sonification should be turned on or off. A value of 0 means that it
// is turned off, and a 1 means that it is turned on. The order of the
// settings can be seen in the table below. If the setting does not exist for
// a planet, the value is always 0.
// msg[4][0] = Size/day. 1 -> Size/day is turned on.
// 0 -> Size/day is turned off.
// msg[4][1] = Gravity
// msg[4][2] = Temperature
// msg[4][3] = Atmosphere
// msg[4][4] = Moons
// msg[4][5] = Rings
// msg[5] = (optional) The distance from the camera to the first moon in kilometers.
// msg[6] = (optional) The horizontal angle in radians to the first moon.
// msg[7] = (optional) The elevation angle in radians to the first moon.
// msg[8] = (optional) The distance from the camera to the second moon in kilometers.
// msg[9] = (optional) The horizontal angle in radians to the second moon.
// msg[10] = (optional) The elevation angle in radians to the second moon.
// msg[...] = The data then continues in the same pattern for each of the planet's
// moons, with three values per moon. The moons are given in order of
// distance from the planet (closest first, farthest last) as specified in
// the planets.asset file in the data\assets\modules\telemetry\sonification
// folder.
// Mercury
OSCdef.new(
\Mercury,
{
arg msg;
// Follow the planets sonification data map above
// Mercury does not have the GUI settings:
// - Atmosphere
// - Moons
// - Rings
// Mercury have no moon data since it does not have any moon
("Mercury: " + msg).postln;
},
'/Mercury'
);
// Venus
OSCdef.new(
\Venus,
{
arg msg;
// Follow the planets sonification data map above
// Venus does not have the GUI settings:
// - Moons
// - Rings
// Venus have no moon data since it does not have any moon
("Venus: " + msg).postln;
},
'/Venus'
);
// Earth
OSCdef.new(
\Earth,
{
arg msg;
// Follow the planets sonification data map above
// Earth does not have the GUI settings:
// - Rings
// Earth have moon data for one moon:
// - The Moon
("Earth: " + msg).postln;
},
'/Earth'
);
// Mars
OSCdef.new(
\Mars,
{
arg msg;
// Follow the planets sonification data map above
// Mars does not have the GUI settings:
// - Rings
// Mars have moon data for 2 moons in the following order:
// - Phobos
// - Deimos
("Mars: " + msg).postln;
},
'/Mars'
);
// Jupiter
OSCdef.new(
\Jupiter,
{
arg msg;
// Follow the planets sonification data map above
// Jupiter does not have the GUI settings:
// - Rings (there are rings in real-life, but not in OpenSpace)
// Jupiter have moon data for 4 moons in the following order:
// - Io
// - Europa
// - Ganymede
// - Callisto
("Jupiter: " + msg).postln;
},
'/Jupiter'
);
// Saturn
OSCdef.new(
\Saturn,
{
arg msg;
// Follow the planets sonification data map above
// Saturn have moon data for 8 moons in the following order:
// - Dione
// - Enceladus
// - Hyperion
// - Iapetus
// - Mimas
// - Rhea
// - Tethys
// - Titan
("Saturn: " + msg).postln;
},
'/Saturn'
);
// Uranus
OSCdef.new(
\Uranus,
{
arg msg;
// Follow the planets sonification data map above
// Uranus does not have the GUI settings:
// - Rings (there are rings in real-life, but not in OpenSpace)
// Uranus have moon data for 5 moons in the following order:
// - Ariel
// - Miranda
// - Oberon
// - Titania
// - Umbriel
("Uranus: " + msg).postln;
},
'/Uranus'
);
// Neptune
OSCdef.new(
\Neptune,
{
arg msg;
// Follow the planets sonification data map above
// Neptune does not have the GUI settings:
// - Rings (there are rings in real-life, but not in OpenSpace)
// Neptune have moon data for 2 moons in the following order:
// - Triton
// - Nereid
("Neptune: " + msg).postln;
},
'/Neptune'
);
)
@@ -0,0 +1,390 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2025 *
* *
* 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. *
****************************************************************************************/
Platform.userExtensionDir
NetAddr.langPort;
NetAddr.localAddr;
/*****************************************************************************************
* This is a SuperCollider file that needs to be run in the SuperCollider application *
* that can be downloaded here: https://supercollider.github.io/ *
* *
* This is an example file for the ISS and Tiangong space stations. This sonification *
* will emit an impulse sound for both stations, with Tiangong having a higher pitch and *
* ISS a lower pitch when the camera is close to either of the space stations. For a *
* more extensive example that shows how to create sounds in SuperCollider based on the *
* data from OpenSpace, see the planets-sonification.scd file located in *
* data\assets\modules\telemetry\sonification. This sonification was made by Elias *
* Elmquist. *
* *
* To run a SuperCollider file, click any line within the parentheses below, such as the *
* marked line. When you have selected a line, press the CTRL and ENTER keys on your *
* keyboard at the same time, and SuperCollider will run the code. You will see several *
* messages appear in the log to the right, the last message should be: *
* "---------- Sonification is ready ----------". At this point, SuperCollider is ready *
* to receive messages from OpenSpace and produce the sonification. For a guide on how *
* to enable and use the Telemetry module inside OpenSpace, see this documentation page: *
* https://docs.openspaceproject.com/latest/creating-data-assets/modules/telemetry/ *
* index.html *
****************************************************************************************/
(
// To run this example, click this line and press CTRL + ENTER on the keyboard
// When finished, press CTRL + . on you keyboard simultaneously to stop the sonification
s.quit;
o = Server.default.options;
// TODO Update this to use the angle calculation setting in OpenSpace
// 0: Stereo (Binaurual)
// 1: VisC Dome
// 2: Hayden
~setup = 0;
if((~setup == 0),
{~numSpeakerChannels = 2;}
);
if((~setup == 1),
{o.outDevice_("ASIO : Focusrite USB ASIO");
~numSpeakerChannels = 8;
}
);
if((~setup == 2),
{o.outDevice_("ASIO : ASIO MADIface USB");
~numSpeakerChannels = 32;
}
);
o.numOutputBusChannels = ~numSpeakerChannels;
//3D
~ampMode = 1;
~focusType = 1;
~lockedFocus = 0;
~comparisonMode = 1;
// Setup which nodes to listen to in OpenSpace
~oscLabel0 = \ISS;
~oscLabel1 = \Tiangong;
s.reboot;
s.waitForBoot{
var loadSynths = {
// Create a sound function to play a poof sound
SynthDef(
\synth,
{
arg out=0, gate=1, mamp=5, amp=0, baseAmp=1, freq=400, buf, loop=0, rate=1, da=0, atk=1, dcay=0, suslvl=1, rel=1, mute=1, trig=0, phase=0;
var sig=0, env, t_gate=0;
t_gate = gate * LFPulse.kr(0.2,phase);
env = EnvGen.kr(
Env.perc(0.01,1/0.5),
t_gate,
doneAction:0
);
sig = BrownNoise.ar(1);
sig = (BPF.ar(sig, freq*2, 0.004) * 50);
sig = mamp * sig;
sig = mute.lag(5) * (baseAmp*amp) * sig * env;
Out.ar(out, sig);
}
).add;
// Setup Ambisonics
~order = 2; // set this to the order you want
~numChannels = ((~order + 1)**2).asInteger;
// binaural decoder (~numChannels -> 2) - reads from 'bus' and sums into 'out'
SynthDef.new(\binauralDecoder, { | bus, out = 0 |
Out.ar(out, VSTPlugin.ar(In.ar(bus, ~numChannels), 2));
}).add;
SynthDef.new(\allraDecoder, { | bus, out = 0 |
Out.ar(out, VSTPlugin.ar(In.ar(bus, ~numChannels), ~numSpeakerChannels));
}).add;
// stereo encoder (2 -> ~numChannels) - replaces stereo signal with ambisonics signal
SynthDef.new(\stereoEncoder, { | bus = 0 |
ReplaceOut.ar(bus, VSTPlugin.ar(In.ar(bus, 2), ~numChannels));
}).add;
// ambisonics insert FX Surround (replaces input with output)
SynthDef.new(\ambiFX, { | bus = 0, bypass |
ReplaceOut.ar(bus, VSTPlugin.ar(In.ar(bus, ~numChannels), ~numChannels, bypass));
}).add;
// helper Synth (throws audio from ambi bus to ambi master bus)
SynthDef.new(\ambiThrow, { | from, to |
Out.ar(to, In.ar(from, ~numChannels));
}).add;
};
var initiateAmbisonic = {
// bus + group
~ambiMasterBus = Bus.audio(s, ~numChannels);
~ambiMasterGroup = Group.new;
if((~setup == 0),
// binaural decoder (writes to master output)
{~decoder = VSTPluginController(Synth(\binauralDecoder, [\bus, ~ambiMasterBus, \out, 0], target: ~ambiMasterGroup, addAction: \addToTail)).open("BinauralDecoder");},
// AllRA decoder
{~decoder = VSTPluginController(Synth(\allraDecoder, [\bus, ~ambiMasterBus, \out, 0], target: ~ambiMasterGroup, addAction: \addToTail)).open("SimpleDecoder");}
);
// ambisonics insert FX (replaces input with output)
SynthDef.new(\ambiFX, { | bus = 0, bypass |
ReplaceOut.ar(bus, VSTPlugin.ar(In.ar(bus, 2), ~numChannels, bypass));
}).add;
// a group for ambisonic master effects
~ambiMasterFXGroup = Group.before(~decoder.synth);
};
var initiateSynths = {
// create ambisonic busses
~soundBus = Array.newClear(7);
~numBus = ~soundBus.size;
~ambiBus = Array.newClear(~numBus);
~ambiGroup = Array.newClear(~numBus);
~encoder = Array.newClear(~numBus);
~sounds = Array.newClear(~numBus);
// First Poof
~ambiBus[0] = Bus.audio(s, ~numChannels);
~ambiGroup[0] = Group.before(~ambiMasterGroup);
~sounds[0] = Synth.new(\synth, [\out, ~ambiBus[0], \freq, 200], ~ambiGroup[0], addAction: \addToHead);
~encoder[0] = VSTPluginController(Synth(\stereoEncoder, [\bus, ~ambiBus[0]], target: ~ambiGroup[0], addAction: \addToTail));
~encoder[0].open("StereoEncoder", action: { |self| self.set(6, 0.5) }); // 6 -> azimuth
Synth(\ambiThrow, [\from, ~ambiBus[0], \to, ~ambiMasterBus], target: ~ambiGroup[0], addAction: \addToTail);
// Second Poof
~ambiBus[1] = Bus.audio(s, ~numChannels);
~ambiGroup[1] = Group.before(~ambiMasterGroup);
~sounds[1] = Synth.new(\synth, [\out, ~ambiBus[1], \freq, 400, \phase, 0.3], ~ambiGroup[1], addAction: \addToHead);
~encoder[1] = VSTPluginController(Synth(\stereoEncoder, [\bus, ~ambiBus[1]], target: ~ambiGroup[1], addAction: \addToTail));
~encoder[1].open("StereoEncoder", action: { |self| self.set(6, 0.6) }); // 6 -> azimuth
Synth(\ambiThrow, [\from, ~ambiBus[1], \to, ~ambiMasterBus], target: ~ambiGroup[1], addAction: \addToTail);
//Audio mixing of the sounds (if needed)
~sounds[0].set(\baseAmp, 0.3);
~sounds[1].set(\baseAmp, 0.3);
// Debugging spatial position
//~encoder[0].editor;
// add an ambisonic master FX
~ambiReverb = VSTPluginController(Synth(\ambiFX, [\bus, ~ambiMasterBus, \out, 0],
target: ~ambiMasterFXGroup)).open("FdnReverb", action: { |self| self.set(1, 0.2) });
};
var loadDecoder = {
if((~setup == 1),
{
~decoder.iemPluginOSC("/SimpleDecoder/loadFile", thisProcess.nowExecutingPath.dirname +/+ "AmbiDecoders" +/+ "DomenVisC_5th.json");
0.1.wait;
~decoder.iemPluginOSC("/SimpleDecoder/swMode", 1);
0.1.wait;
~decoder.iemPluginOSC("/SimpleDecoder/swChannel", 4);
0.1.wait;
~decoder.iemPluginOSC("/SimpleDecoder/lowPassGain", -12);
}
);
if((~setup == 2),
{
~decoder.iemPluginOSC("/SimpleDecoder/loadFile", thisProcess.nowExecutingPath.dirname +/+ "AmbiDecoders" +/+ "HaydenIEM_5th_0deg_80top_rot180deg.json");
0.1.wait;
~decoder.iemPluginOSC("/SimpleDecoder/swMode", 1);
0.1.wait;
~decoder.iemPluginOSC("/SimpleDecoder/swChannel", 32);
0.1.wait;
}
);
};
// Set which OSC labels to listen to
var oscDef = {
//Horizontal mode
~modeElSign = 1;
~modeElPhase = 0.5;
//Circular mode (switch manually)
//~modeElSign = -1;
//~modeElPhase = 0.75;
//Size of hearable area
~distanceLimit = 10;
//Ambient amp
~ambientAmp = 1.0;
OSCdef.new(\Mode,
{
arg msg;
//msg[1] == 0 -> Horizontal
//msg[1] == 1 -> Circular
//msg[2] == 0 -> Elevation on
//msg[2] == 1 -> Elevation off
("SurroundMode:" + msg[1]).postln;
//Horizontal
if(((msg[1]==0)),
{~modeElSign = 1;
~modeElPhase = 0.5;},
{}
);
//Circular
if(((msg[1]==1)),
{~modeElSign = -1;
~modeElPhase = 0.75;},
{}
);
("~modeElSign:" + ~modeElSign).postln;
("~modeElPhase:" + ~modeElPhase).postln;
},'/Mode');
OSCdef.new(
~oscLabel0,
{
arg msg;
var name, distance, invDistance, azimuth, amp, value, elevation;
//msg[1]: label distance
//msg[2]: label azimuth
//msg[3]: label elevation
// DEBUG: Uncomment this line to get console output of all messages from OpenSpace
//(~oscLabel0 ++ ": " ++ msg).postln;
name = msg[0].asString;
distance = msg[1]/1000000;
//invDistance = ~distanceLimit-distance;
azimuth = (msg[2]/(2*pi))+0.5;
elevation = ~modeElSign*(msg[3]/(2*pi))+~modeElPhase;
if((~ampMode == 1),
{
if((distance < ~distanceLimit),
{amp = LinLin.kr(distance, 0, ~distanceLimit, 0, 1);
},
{amp = ~ambientAmp;}
);
}
);
(~oscLabel0 ++ "Amp: " ++ amp).postln;
~sounds[0].set(\amp, amp);
~encoder[0].do(_.set(6, azimuth));
~encoder[0].do(_.set(7, elevation));
},
~oscLabel0
);
OSCdef.new(
~oscLabel1,
{
arg msg;
var name, distance, invDistance, azimuth, amp, value, elevation;
//msg[1]: label distance
//msg[2]: label azimuth
//msg[3]: label elevation
// DEBUG: Uncomment this line to get console output of messages from OpenSpace
//(~oscLabel1 ++ ": " ++ msg).postln;
name = msg[0].asString;
distance = msg[1]/10000;
//invDistance = ~distanceLimit-distance;
azimuth = (msg[2]/(2*pi))+0.5;
elevation = ~modeElSign*(msg[3]/(2*pi))+~modeElPhase;
if((~ampMode == 1),
{
if((distance < ~distanceLimit),
{amp = LinLin.kr(distance, 0, ~distanceLimit, 0, 1);
},
{amp = ~ambientAmp;}
);
}
);
(~oscLabel1 ++ "Amp: " ++ amp).postln;
~sounds[1].set(\amp, amp);
~encoder[1].do(_.set(6, azimuth));
~encoder[1].do(_.set(7, elevation));
},
~oscLabel1
);
};
// Start routine
~startRoutine = Routine({
0.5.wait;
loadSynths.value;
"--Loaded the synths--".postln;
0.3.wait;
initiateAmbisonic.value;
"--Loaded the ambisonics--".postln;
0.3.wait;
initiateSynths.value;
"--Initiated the synths--".postln;
0.2.wait;
loadDecoder.value;
"--Loaded the decoder--".postln;
0.2.wait;
oscDef.value;
"--Loaded the OSCdefs--".postln;
"---------- Sonification is ready ----------".postln;
});
~startRoutine.play(AppClock);
}
)
@@ -0,0 +1,402 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2025 *
* *
* 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. *
****************************************************************************************/
Platform.userExtensionDir
NetAddr.langPort;
NetAddr.localAddr;
/*****************************************************************************************
* This is a SuperCollider file that needs to be run in the SuperCollider application *
* that can be downloaded here: https://supercollider.github.io/ *
* *
* This is an example file for the Voyager 1 and 2 space probes. This sonification will *
* play and loop the Greetings to the Universe audio clip (one of the recordings *
* included on the Golden Records aboard both probes) when the camera is close to either *
* of the probes. For a more extensive example that shows how to create sounds in *
* SuperCollider based on the data from OpenSpace, see the planets-sonification.scd file *
* located in data\assets\modules\telemetry\sonification. This sonification was made by *
* Elias Elmquist. *
* *
* To run a SuperCollider file, click any line within the parentheses below, such as the *
* marked line. When you have selected a line, press the CTRL and ENTER keys on your *
* keyboard at the same time, and SuperCollider will run the code. You will see several *
* messages appear in the log to the right, the last message should be: *
* "---------- Sonification is ready ----------". At this point, SuperCollider is ready *
* to receive messages from OpenSpace and produce the sonification. For a guide on how *
* to enable and use the Telemetry module inside OpenSpace, see the documentation page: *
* https://docs.openspaceproject.com/latest/creating-data-assets/modules/telemetry/ *
* index.html *
****************************************************************************************/
(
// To run this example, click this line and press CTRL + ENTER on the keyboard
// When finished, press CTRL + . on you keyboard simultaneously to stop the sonification
s.quit;
o = Server.default.options;
// TODO Update this to use the angle calculation setting in OpenSpace
// Set the surround setting
// 0: Stereo (Binaurual)
// 1: VisC Dome
// 2: Hayden
~setup = 0;
if((~setup == 0),
{~numSpeakerChannels = 2;}
);
if((~setup == 1),
{o.outDevice_("ASIO : Focusrite USB ASIO");
~numSpeakerChannels = 8;
}
);
if((~setup == 2),
{o.outDevice_("ASIO : ASIO MADIface USB");
~numSpeakerChannels = 32;
}
);
o.numOutputBusChannels = ~numSpeakerChannels;
//3D
~ampMode = 1;
~focusType = 1;
~lockedFocus = 0;
~comparisonMode = 1;
// Setup which nodes to listen to in OpenSpace
~oscLabel0 = \Voyager_1;
~oscLabel1 = \Voyager_2;
s.reboot;
s.waitForBoot{
// Load the Greetings to the Universe audio clip (located next to this file)
var filePath = thisProcess.nowExecutingPath.dirname;
var loadSamples = {
~b1 = Buffer.read(s, filePath +/+ "Greetings_from_Earth_mono.wav");
// To load another audio clip, copy the line above, change the variable name
// and the path to the audio file
};
var loadSynths = {
// Create a sound function to play and loop the audio clip
SynthDef(
\audiofile,
{
arg out=0, gate=1, mamp=5, amp=0, baseAmp=1, buf, loop=0, rate=1, da=0, atk=1, dcay=0, suslvl=1, rel=1, mute=1, trig=0;
var sig=0, env;
env = EnvGen.kr(
Env.adsr(atk,dcay,suslvl,rel),
gate,
doneAction:da
);
sig = PlayBuf.ar(1, buf, rate:rate, loop:loop, trigger:trig);
sig = mamp * sig;
sig = mute.lag(5) * (baseAmp*amp) * sig * env;
Out.ar(out, sig);
}
).add;
// Setup Ambisonics
~order = 2; // set this to the order you want
~numChannels = ((~order + 1)**2).asInteger;
// binaural decoder (~numChannels -> 2) - reads from 'bus' and sums into 'out'
SynthDef.new(\binauralDecoder, { | bus, out = 0 |
Out.ar(out, VSTPlugin.ar(In.ar(bus, ~numChannels), 2));
}).add;
SynthDef.new(\allraDecoder, { | bus, out = 0 |
Out.ar(out, VSTPlugin.ar(In.ar(bus, ~numChannels), ~numSpeakerChannels));
}).add;
// stereo encoder (2 -> ~numChannels) - replaces stereo signal with ambisonics signal
SynthDef.new(\stereoEncoder, { | bus = 0 |
ReplaceOut.ar(bus, VSTPlugin.ar(In.ar(bus, 2), ~numChannels));
}).add;
// ambisonics insert FX Surround (replaces input with output)
SynthDef.new(\ambiFX, { | bus = 0, bypass |
ReplaceOut.ar(bus, VSTPlugin.ar(In.ar(bus, ~numChannels), ~numChannels, bypass));
}).add;
// helper Synth (throws audio from ambi bus to ambi master bus)
SynthDef.new(\ambiThrow, { | from, to |
Out.ar(to, In.ar(from, ~numChannels));
}).add;
};
var initiateAmbisonic = {
// bus + group
~ambiMasterBus = Bus.audio(s, ~numChannels);
~ambiMasterGroup = Group.new;
if((~setup == 0),
// binaural decoder (writes to master output)
{~decoder = VSTPluginController(Synth(\binauralDecoder, [\bus, ~ambiMasterBus, \out, 0], target: ~ambiMasterGroup, addAction: \addToTail)).open("BinauralDecoder");},
// AllRA decoder
{~decoder = VSTPluginController(Synth(\allraDecoder, [\bus, ~ambiMasterBus, \out, 0], target: ~ambiMasterGroup, addAction: \addToTail)).open("SimpleDecoder");}
);
// ambisonics insert FX (replaces input with output)
SynthDef.new(\ambiFX, { | bus = 0, bypass |
ReplaceOut.ar(bus, VSTPlugin.ar(In.ar(bus, 2), ~numChannels, bypass));
}).add;
// a group for ambisonic master effects
~ambiMasterFXGroup = Group.before(~decoder.synth);
};
var initiateSynths = {
// create ambisonic busses
~soundBus = Array.newClear(7);
~numBus = ~soundBus.size;
~ambiBus = Array.newClear(~numBus);
~ambiGroup = Array.newClear(~numBus);
~encoder = Array.newClear(~numBus);
~sounds = Array.newClear(~numBus);
// First Audio clip
~ambiBus[0] = Bus.audio(s, ~numChannels);
~ambiGroup[0] = Group.before(~ambiMasterGroup);
~sounds[0] = Synth.new(\audiofile, [\out, ~ambiBus[0], \buf, ~b1], ~ambiGroup[0], addAction: \addToHead);
~encoder[0] = VSTPluginController(Synth(\stereoEncoder, [\bus, ~ambiBus[0]], target: ~ambiGroup[0], addAction: \addToTail));
~encoder[0].open("StereoEncoder", action: { |self| self.set(6, 0.5) }); // 6 -> azimuth
Synth(\ambiThrow, [\from, ~ambiBus[0], \to, ~ambiMasterBus], target: ~ambiGroup[0], addAction: \addToTail);
// Second Audio clip (if needed)
/*~ambiBus[1] = Bus.audio(s, ~numChannels);
~ambiGroup[1] = Group.before(~ambiMasterGroup);
~sounds[1] = Synth.new(\audiofile, [\out, ~ambiBus[1], \buf, ~b2], ~ambiGroup[1], addAction: \addToHead);
~encoder[1] = VSTPluginController(Synth(\stereoEncoder, [\bus, ~ambiBus[1]], target: ~ambiGroup[1], addAction: \addToTail));
~encoder[1].open("StereoEncoder", action: { |self| self.set(6, 0.6) }); // 6 -> azimuth
Synth(\ambiThrow, [\from, ~ambiBus[1], \to, ~ambiMasterBus], target: ~ambiGroup[1], addAction: \addToTail);
//Audio mixing of the sounds (if needed)
~sounds[0].set(\baseAmp, 0.3);
~sounds[1].set(\baseAmp, 0.3);*/
// Debugging spatial position
//~encoder[0].editor;
~sounds[0].set(\baseAmp, 0.3);
// add an ambisonic master FX
~ambiReverb = VSTPluginController(Synth(\ambiFX, [\bus, ~ambiMasterBus, \out, 0],
target: ~ambiMasterFXGroup)).open("FdnReverb", action: { |self| self.set(1, 0.2) });
};
var loadDecoder = {
if((~setup == 1),
{
~decoder.iemPluginOSC("/SimpleDecoder/loadFile", thisProcess.nowExecutingPath.dirname +/+ "AmbiDecoders" +/+ "DomenVisC_5th.json");
0.1.wait;
~decoder.iemPluginOSC("/SimpleDecoder/swMode", 1);
0.1.wait;
~decoder.iemPluginOSC("/SimpleDecoder/swChannel", 4);
0.1.wait;
~decoder.iemPluginOSC("/SimpleDecoder/lowPassGain", -12);
}
);
if((~setup == 2),
{
~decoder.iemPluginOSC("/SimpleDecoder/loadFile", thisProcess.nowExecutingPath.dirname +/+ "AmbiDecoders" +/+ "HaydenIEM_5th_0deg_80top_rot180deg.json");
0.1.wait;
~decoder.iemPluginOSC("/SimpleDecoder/swMode", 1);
0.1.wait;
~decoder.iemPluginOSC("/SimpleDecoder/swChannel", 32);
0.1.wait;
}
);
};
// Set which OSC labels to listen to
var oscDef = {
//Horizontal mode
~modeElSign = 1;
~modeElPhase = 0.5;
//Circular mode (switch manually)
//~modeElSign = -1;
//~modeElPhase = 0.75;
//Size of hearable area
~distanceLimit = 0.5;
//Ambient amp
~ambientAmp = 1.0;
OSCdef.new(\Mode,
{
arg msg;
//msg[1] == 0 -> Horizontal
//msg[1] == 1 -> Circular
//msg[2] == 0 -> Elevation on
//msg[2] == 1 -> Elevation off
("SurroundMode:" + msg[1]).postln;
//Horizontal
if(((msg[1]==0)),
{~modeElSign = 1;
~modeElPhase = 0.5;},
{}
);
//Circular
if(((msg[1]==1)),
{~modeElSign = -1;
~modeElPhase = 0.75;},
{}
);
("~modeElSign:" + ~modeElSign).postln;
("~modeElPhase:" + ~modeElPhase).postln;
},'/Mode');
OSCdef.new(
~oscLabel0,
{
arg msg;
var name, distance, invDistance, azimuth, amp, value, elevation;
//msg[1]: label distance
//msg[2]: label azimuth
//msg[3]: label elevation
// DEBUG: Uncomment this line to get console output of all messages from OpenSpace
//(~oscLabel0 ++ ": " ++ msg).postln;
name = msg[0].asString;
distance = msg[1]/1000000;
//invDistance = ~distanceLimit-distance;
azimuth = (msg[2]/(2*pi))+0.5;
elevation = ~modeElSign*(msg[3]/(2*pi))+~modeElPhase;
if((~ampMode == 1),
{
if((distance < ~distanceLimit),
{amp = LinLin.kr(distance, 0, ~distanceLimit, 0, 1);
},
{amp = ~ambientAmp;}
);
}
);
(~oscLabel0 ++ "Amp: " ++ amp).postln;
~sounds[0].set(\amp, amp);
~encoder[0].do(_.set(6, azimuth));
~encoder[0].do(_.set(7, elevation));
},
~oscLabel0
);
OSCdef.new(
~oscLabel1,
{
arg msg;
var name, distance, invDistance, azimuth, amp, value, elevation;
//msg[1]: label distance
//msg[2]: label azimuth
//msg[3]: label elevation
// DEBUG: Uncomment this line to get console output of all messages from OpenSpace
//(~oscLabel1 ++ ": " ++ msg).postln;
name = msg[0].asString;
distance = msg[1]/1000000;
//invDistance = ~distanceLimit-distance;
azimuth = (msg[2]/(2*pi))+0.5;
elevation = ~modeElSign*(msg[3]/(2*pi))+~modeElPhase;
if((~ampMode == 1),
{
if((distance < ~distanceLimit),
{amp = LinLin.kr(distance, 0, ~distanceLimit, 0, 1);
},
{amp = ~ambientAmp;}
);
}
);
(~oscLabel1 ++ "Amp: " ++ amp).postln;
~sounds[0].set(\amp, amp);
~encoder[0].do(_.set(6, azimuth));
~encoder[0].do(_.set(7, elevation));
},
~oscLabel1
);
};
// Start routine
~startRoutine = Routine({
0.5.wait;
loadSamples.value;
"--Loaded the data--".postln;
0.2.wait;
loadSynths.value;
"--Loaded the synths--".postln;
0.3.wait;
initiateAmbisonic.value;
"--Loaded the ambisonics--".postln;
0.3.wait;
initiateSynths.value;
"--Initiated the synths--".postln;
0.2.wait;
loadDecoder.value;
"--Loaded the decoder--".postln;
0.2.wait;
oscDef.value;
"--Loaded the OSCdefs--".postln;
"---------- Sonification is ready ----------".postln;
});
~startRoutine.play(AppClock);
}
)
@@ -0,0 +1,44 @@
-- CK Multiple
-- This example creates a time frame based on the information provided by multiple SPICE
-- kernel files that contain orientation information about the same object. The created
-- scene graph node will only be valid whenever any window in any of the provided kernels
-- contains information about refernence frame "-98000", which is the intertial
-- orientation frame for the New Horizons spacecraft.
-- We need a SPICE kernel to work with in this example
local data = asset.resource({
Name = "New Horizons Kernels",
Type = "HttpSynchronization",
Identifier = "newhorizons_kernels",
Version = 1
})
local Node = {
Identifier = "TimeFrameKernel_Example_CK_Multiple",
TimeFrame = {
Type = "TimeFrameKernel",
CK = {
Kernels = {
data .. "nh_apf_20150404_20150420_001.bc",
data .. "nh_apf_20150420_20150504_001.bc",
data .. "new-horizons_1121.tsc"
},
Reference = "-98000"
}
},
Renderable = {
Type = "RenderableCartesianAxes"
},
GUI = {
Name = "TimeFrameKernel - Basic (CK, Multiple)",
Path = "/Examples"
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(Node)
end)
@@ -0,0 +1,42 @@
-- CK Basic
-- This example creates a time frame based on the information provided by a single SPICE
-- kernel file. The created scene graph node will only be valid whenever the provided
-- kernel contains information about about the reference frame "-98000", which is the
-- interial orientation frame for the New Horizons spacecraft.
-- We need a SPICE kernel to work with in this example
local data = asset.resource({
Name = "New Horizons Kernels",
Type = "HttpSynchronization",
Identifier = "newhorizons_kernels",
Version = 1
})
local Node = {
Identifier = "TimeFrameKernel_Example_CK",
TimeFrame = {
Type = "TimeFrameKernel",
CK = {
Kernels = {
data .. "nh_apf_20150404_20150420_001.bc",
data .. "new-horizons_1121.tsc",
},
Reference = "-98000"
}
},
Renderable = {
Type = "RenderableCartesianAxes"
},
GUI = {
Name = "TimeFrameKernel - Basic (CK)",
Path = "/Examples"
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(Node)
end)
@@ -0,0 +1,48 @@
-- Combined example
-- This example creates a time frame based on the information provided by multiple SPICE
-- kernel files. The created scene graph node will only be valid whenever the provided
-- kernels contain information positional information about the object "JUICE" as well as
-- orientation information for the reference frame "-28002" which is the measured attitude
-- for the JUICE spacecraft. The time frame will only be valid if both pieces of data are
-- available.
-- We need a SPICE kernel to work with in this example
local data = asset.resource({
Name = "JUICE Kernels",
Type = "HttpSynchronization",
Identifier = "juice_kernels",
Version = 2
})
local Node = {
Identifier = "TimeFrameKernel_Example_Combined_SPK-CK",
TimeFrame = {
Type = "TimeFrameKernel",
SPK = {
Kernels = data .. "juice_orbc_000031_230414_310721_v03.bsp",
Object = "JUICE"
},
CK = {
Kernels = {
data .. "juice_sc_meas_230413_230415_s230414_v01.bc",
data .. "juice_step_230414_v01.tsc"
},
Reference = "-28002"
}
},
Renderable = {
Type = "RenderableCartesianAxes"
},
GUI = {
Name = "TimeFrameKernel - Combined (SPK+CK)",
Path = "/Examples"
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(Node)
end)
@@ -0,0 +1,42 @@
-- SPK Multiple
-- This example creates a time frame based on the information provided by multiple SPICE
-- kernel files that contain position information about the same object. The created scene
-- graph node will only be valid whenever any window in any of the provided kernels
-- contains information about object "VOYAGER 1".
-- We need a SPICE kernel to work with in this example
local data = asset.resource({
Name = "Voyager 1 Kernels",
Type = "HttpSynchronization",
Identifier = "voyager1_spice",
Version = 2
})
local Node = {
Identifier = "TimeFrameKernel_Example_SPK_Multiple",
TimeFrame = {
Type = "TimeFrameKernel",
SPK = {
Kernels = {
data .. "vgr1_jup230.bsp",
data .. "vgr1_sat337.bsp"
},
Object = "VOYAGER 1"
}
},
Renderable = {
Type = "RenderableCartesianAxes"
},
GUI = {
Name = "TimeFrameKernel - Basic (SPK, Multiple)",
Path = "/Examples"
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(Node)
end)
@@ -0,0 +1,40 @@
-- SPK Basic
-- This example creates a time frame based on the information provided by a single SPICE
-- kernel file. The created scene graph node will only be valid whenever the provided
-- kernel contains information about object "-915", which is Apollo 15. In this specific
-- case, the Apollo15 kernel contains two windows of valid data, both of which are used by
-- this time frame.
-- We need a SPICE kernel to work with in this example
local data = asset.resource({
Name = "Apollo Kernels",
Type = "HttpSynchronization",
Identifier = "apollo_spice",
Version = 1
})
local Node = {
Identifier = "TimeFrameKernel_Example_SPK",
TimeFrame = {
Type = "TimeFrameKernel",
SPK = {
Kernels = data .. "apollo15-1.bsp",
Object = "-915"
}
},
Renderable = {
Type = "RenderableCartesianAxes"
},
GUI = {
Name = "TimeFrameKernel - Basic (SPK)",
Path = "/Examples"
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(Node)
end)
@@ -1,5 +1,4 @@
asset.onInitialize(function()
openspace.setPropertyValueSingle("Modules.Exoplanets.Enabled", true)
openspace.setPropertyValueSingle("Modules.Exoplanets.ShowComparisonCircle", false)
openspace.setPropertyValueSingle("Modules.Exoplanets.ShowHabitableZone", true)
openspace.setPropertyValueSingle("Modules.Exoplanets.UseOptimisticZone", true)
@@ -1,15 +0,0 @@
asset.onInitialize(function()
openspace.setPropertyValueSingle("Modules.SkyBrowser.Enabled", true)
openspace.setPropertyValueSingle("Modules.SkyBrowser.ShowTitleInGuiBrowser", false)
-- More settings are available, but for now using the default values
end)
asset.meta = {
Name = "SkyBrowser Module Default Settings",
Description = "Some default settings related to the SkyBrowser module",
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license"
}
@@ -1,2 +1 @@
asset.require("./default_settings")
asset.require("./hover_circle")
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,81 @@
-- For more information about sonification in OpenSpace and how to use it, see the
-- documentation:
-- https://docs.openspaceproject.com/latest/creating-data-assets/modules/telemetry/sonification.html
asset.require("scene/solarsystem/planets/planets")
asset.onInitialize(function ()
-- Note that the planets need to be in this order
local planets = {
{
Name = "Mercury"
},
{
Name = "Venus"
},
{
Name = "Earth",
Moons = {
"Moon"
}
},
{
Name = "Mars",
Moons = {
"Phobos",
"Deimos"
}
},
{
Name = "Jupiter",
Moons = {
"Io",
"Europa",
"Ganymede",
"Callisto"
}
},
{
Name = "Saturn",
Moons = {
"Dione",
"Enceladus",
"Hyperion",
"Iapetus",
"Mimas",
"Rhea",
"Tethys",
"Titan"
}
},
{
Name = "Uranus",
Moons = {
"Ariel",
"Miranda",
"Oberon",
"Titania",
"Umbriel"
}
},
{
Name = "Neptune",
Moons = {
"Triton",
"Nereid"
}
}
}
openspace.sonification.addPlanets(planets)
end)
asset.meta = {
Name = "PlanetSonification planets",
Version = "1.0",
Description = "The list of planets in the PlanetSonification",
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license"
}
+45
View File
@@ -2,6 +2,14 @@ local earthAsset = asset.require("scene/solarsystem/planets/earth/earth")
local labels = asset.resource({
Name = "AltAz Label Files",
Type = "HttpSynchronization",
Identifier = "alt_az_labels",
Version = 1
})
local AltAzGridPosition = {
Identifier = "AltAzGridPosition",
Parent = earthAsset.Earth.Identifier,
@@ -52,6 +60,7 @@ local AltAzGrid = {
LineWidth = 2.0,
RenderBinMode = "PostDeferredTransparent"
},
Tag = { "nightsky_marking" },
GUI = {
Name = "Altitude-Azimuth Grid",
Description = [[A local Altitude/Azimuth grid centered around your position on a
@@ -62,6 +71,39 @@ local AltAzGrid = {
}
}
local AltAzGridLabels = {
Identifier = "AltAzGridLabels",
Parent = AltAzGridPosition.Identifier,
Transform = {
Rotation = {
Type = "StaticRotation",
Rotation = { -math.pi / 2.0, math.pi, 0.0 }
}
},
Renderable = {
Type = "RenderablePointCloud",
Enabled = false,
Labels = {
Enabled = true,
File = labels .. "eclip.label",
Color = { 0.5, 0.5, 0.5 },
FaceCamera = false,
Size = 14.8,
MinMaxSize = { 2, 70 },
Unit = "pc",
},
Opacity = 0.65,
RenderBinMode = "PostDeferredTransparent"
},
Tag = { "nightsky_marking" },
GUI = {
Name = "Altitude-Azimuth Grid Labels",
Description = [[Labels for the Altitude-Azimuth Grid]],
Path = "/Night Sky/Coordinate Systems/Altitude-Azimuth"
}
}
local ShowAltaz = {
Identifier = "os.nightsky.ShowAltaz",
Name = "Show Alt/Az grid",
@@ -105,6 +147,7 @@ local ToggleAltaz = {
asset.onInitialize(function()
openspace.addSceneGraphNode(AltAzGridPosition)
openspace.addSceneGraphNode(AltAzGrid)
openspace.addSceneGraphNode(AltAzGridLabels)
openspace.action.registerAction(ShowAltaz)
openspace.action.registerAction(HideAltaz)
openspace.action.registerAction(ToggleAltaz)
@@ -115,12 +158,14 @@ asset.onDeinitialize(function()
openspace.action.removeAction(ToggleAltaz)
openspace.action.removeAction(HideAltaz)
openspace.action.removeAction(ShowAltaz)
openspace.removeSceneGraphNode(AltAzGridLabels)
openspace.removeSceneGraphNode(AltAzGrid)
openspace.removeSceneGraphNode(AltAzGridPosition)
end)
asset.export(AltAzGridPosition)
asset.export(AltAzGrid)
asset.export(AltAzGridLabels)
asset.export("ShowAltaz", ShowAltaz.Identifier)
asset.export("HideAltaz", HideAltaz.Identifier)
asset.export("ToggleAltaz", ToggleAltaz.Identifier)
@@ -56,8 +56,10 @@ local CardinalDirectionSphere = {
Texture = textures .. "nesw_red.png",
Orientation = "Inside",
MirrorTexture = true,
RenderBinMode = "PostDeferredTransparent"
RenderBinMode = "PostDeferredTransparent",
DisableDepth = true
},
Tag = {"nightsky_marking"},
GUI = {
Name = "Cardinal Directions",
Description = [[A textured sphere showing the cardinal directions.
+3 -1
View File
@@ -34,9 +34,10 @@ local EclipticLine = {
Opacity = 0.8,
Color = { 0.5, 0.24, 0.24 },
LineWidth = 4.0,
GridSegments = { 1, 1 },
GridSegments = {1 , 1},
Enabled = asset.enabled
},
Tag = { "nightsky_marking" },
GUI = {
Name = "Ecliptic",
Description = "A line representation of the Ecliptic plane.",
@@ -63,6 +64,7 @@ local EclipticBand = {
Opacity = 0.05,
Enabled = asset.enabled
},
Tag = { "nightsky_marking" },
GUI = {
Name = "Ecliptic Band",
Description = "A band representation of the Ecliptic plane.",
+2 -1
View File
@@ -27,9 +27,10 @@ local EquatorialLine = {
Opacity = 0.8,
Color = { 0.6, 0.6, 0.2 },
LineWidth = 4.0,
GridSegments = { 1, 1 },
GridSegments = {1, 1},
Enabled = asset.enabled
},
Tag = { "nightsky_marking" },
GUI = {
Name = "Celestial Equator",
Description = "A line representation of the Equatorial plane.",
+1
View File
@@ -19,6 +19,7 @@ local GalacticLine = {
GridSegments = { 1, 1 },
Enabled = asset.enabled
},
Tag = { "nightsky_marking" },
GUI = {
Name = "Galactic Equator",
Description = "A line representation of the Galactic Equator plane.",
+3 -2
View File
@@ -22,6 +22,7 @@ local MeridianPosition = {
UseCamera = true
}
},
Tag = { "nightsky_marking" },
GUI = {
Name = "Local Meridian Position",
Path = "/Night Sky/Coordinate Systems/Altitude-Azimuth",
@@ -44,9 +45,9 @@ local MeridianPlane = {
Color = { 0.4, 0.8, 0.4 },
LineWidth = 6.0,
GridSegments = { 1, 1 },
Enabled = asset.enabled,
RenderBinMode = "PostDeferredTransparent"
Enabled = asset.enabled
},
Tag = { "nightsky_marking" },
GUI = {
Name = "Local Meridian",
Description = [[A line representation of the Local Meridian]],
+4
View File
@@ -9,6 +9,10 @@ asset.require("./zenith", false)
asset.require("./planets", false)
asset.require("actions/nightsky/camera", false)
asset.require("actions/nightsky/daytime", false)
asset.require("actions/nightsky/createsuntrails", false)
asset.require("actions/nightsky/misc", false)
asset.require("actions/nightsky/position", false)
asset.require("actions/time", false)
+75 -25
View File
@@ -13,17 +13,33 @@ local textures = asset.resource({
Version = 1
})
local csv = asset.resource({
Name = "Zero Point Data",
Type = "HttpSynchronization",
Identifier = "zeropoint_data",
Version = 1
})
local Mercury = {
Identifier = "NightSkyMercury",
Parent = mercury.MercuryBarycenter.Identifier,
Renderable = {
Type = "RenderablePlaneImageLocal",
Billboard = true,
Type = "RenderablePointCloud",
File = csv .. "zeropointdata.csv",
Coloring = {
FixedColor = { 0.608, 0.604, 0.455 }
},
Texture = {
File = textures .. "glare.png"
},
SizeSettings = {
ScaleFactor = 10,
ScaleExponent = 15,
MaxSize = 0.209,
EnableMaxSizeControl = true
},
Enabled = asset.enabled,
Size = 2439700 * 500,
Texture = textures .. "glare.png",
MultiplyColor = { 0.608, 0.604, 0.455 },
DimInAtmosphere = true,
RenderBinMode = "PostDeferredTransparent"
},
@@ -41,12 +57,21 @@ local Venus = {
Identifier = "NightSkyVenus",
Parent = venus.VenusBarycenter.Identifier,
Renderable = {
Type = "RenderablePlaneImageLocal",
Type = "RenderablePointCloud",
File = csv .. "zeropointdata.csv",
Coloring = {
FixedColor = { 1.0 , 0.992, 0.757 }
},
Texture = {
File = textures .. "glare.png"
},
SizeSettings = {
ScaleFactor = 10,
ScaleExponent = 15,
MaxSize = 1.14,
EnableMaxSizeControl = true
},
Enabled = asset.enabled,
Billboard = true,
Size = 6051900 * 700,
Texture = textures .. "glare.png",
MultiplyColor = { 1.0 , 0.992, 0.757 },
DimInAtmosphere = true,
RenderBinMode = "PostDeferredTransparent"
},
@@ -64,12 +89,21 @@ local Mars = {
Identifier = "NightSkyMars",
Parent = mars.MarsBarycenter.Identifier,
Renderable = {
Type = "RenderablePlaneImageLocal",
Type = "RenderablePointCloud",
File = csv .. "zeropointdata.csv",
Coloring = {
FixedColor = { 0.756, 0.267, 0.054 }
},
Texture = {
File = textures .. "glare.png"
},
SizeSettings = {
ScaleFactor = 10,
ScaleExponent = 15,
MaxSize = 0.404, --mars max angular size / 62
EnableMaxSizeControl = true
},
Enabled = asset.enabled,
Billboard = true,
Size = 3396190 * 1000,
Texture = textures .. "glare.png",
MultiplyColor = { 0.756, 0.267, 0.054 },
DimInAtmosphere = true,
RenderBinMode = "PostDeferredTransparent"
},
@@ -85,12 +119,21 @@ local Jupiter = {
Identifier = "NightSkyJupiter",
Parent = jupiter.JupiterBarycenter.Identifier,
Renderable = {
Type = "RenderablePlaneImageLocal",
Type = "RenderablePointCloud",
File = csv .. "zeropointdata.csv",
Coloring = {
FixedColor = { 0.608, 0.604, 0.455 },
},
Texture = {
File = textures .. "glare.png"
},
SizeSettings = {
ScaleFactor = 10,
ScaleExponent = 15,
MaxSize = 0.82,
EnableMaxSizeControl = true
},
Enabled = asset.enabled,
Billboard = true,
Size = 71492000 * 400,
Texture = textures .. "glare.png",
MultiplyColor = { 0.608, 0.604, 0.455 },
DimInAtmosphere = true,
RenderBinMode = "PostDeferredTransparent"
},
@@ -108,12 +151,19 @@ local Saturn = {
Identifier = "NightSkySaturn",
Parent = saturn.SaturnBarycenter.Identifier,
Renderable = {
Type = "RenderablePlaneImageLocal",
Type = "RenderablePointCloud",
File = csv .. "zeropointdata.csv",
Coloring = {
FixedColor = { 0.85098, 0.843137, 0.619608 },
},
Texture = {
File = textures .. "glare.png"
},
SizeSettings = {
MaxSize = 0.332,
EnableMaxSizeControl = true
},
Enabled = asset.enabled,
Billboard = true,
Size = 60268000 * 500,
Texture = textures .. "glare.png",
MultiplyColor = { 0.608, 0.604, 0.455 },
DimInAtmosphere = true,
RenderBinMode = "PostDeferredTransparent"
},
+2
View File
@@ -31,6 +31,7 @@ local ZenithPosition = {
UseCamera = true
}
},
Tag = { "nightsky_marking" },
GUI = {
Name = "Zenith Position",
Path = "/Night Sky/Coordinate Systems/Altitude-Azimuth",
@@ -56,6 +57,7 @@ local ZenithDot = {
Texture = textures .. "point3A.png",
BlendMode = "Additive"
},
Tag = { "nightsky_marking" },
GUI = {
Name = "Zenith",
Description = [[A dot representation of the Local Zenith, based on the camera's
+1 -1
View File
@@ -42,7 +42,7 @@ local Object = {
},
GUI = {
Name = "6dF Galaxies",
Path = "/Universe/Deep Sky Surveys",
Path = "/Universe/Nearby Surveys",
Description = [[The Six-degree Field (6dF) Galaxy Survey mapped nearly half the sky
from the Anglo-Australian Observatory. Because it's a southern hemisphere survey,
there is no coverage in these data for the northern hemisphere's sky. As with all
@@ -28,7 +28,7 @@ local Object = {
DisableDepth = true
},
GUI = {
Name = "Hydrogen Alpha",
Name = "Hydrogen-alpha All-sky",
Path = "/Milky Way/All Sky Images",
Description = [[Hydrogen-alpha is a term that describes light from the ground state of
the hydrogen atom. When an electron in an atom moves from one energy level to a
@@ -29,7 +29,7 @@ local Object = {
},
Tag = { "daytime_hidden" },
GUI = {
Name = "Visible Milky Way",
Name = "Visible All-sky",
Path = "/Milky Way/All Sky Images",
Description = [[An all-sky image of the night sky as our eye sees it (in the visible
spectrum), with the stars removed. You will see the brightest part of the Galaxy if
@@ -35,7 +35,7 @@ local COBE = {
DisableDepth = true
},
GUI = {
Name = "1990 COBE CMB",
Name = "COBE",
Path = "/Universe/Cosmic Microwave Background",
Description = [[In 1990, COBE, the Cosmic Background Explorer, took the first
detailed map of the cosmic microwave background light. The red areas are
@@ -69,7 +69,7 @@ local WMAP = {
DisableDepth = true
},
GUI = {
Name = "2003 WMAP CMB",
Name = "WMAP",
Path = "/Universe/Cosmic Microwave Background",
Description = [[WMAP, the Wilkinson Microwave Anisotropy Probe, released this all-sky
image of the cosmic microwave background light in 2003. The blue colors are slightly
@@ -102,7 +102,7 @@ local Planck = {
DisableDepth = true
},
GUI = {
Name = "2013 Planck CMB",
Name = "Planck",
Path = "/Universe/Cosmic Microwave Background",
Description = [[The Planck mission's 2013 image of the cosmic microwave background
light release is the most detailed view of the CMB we have to date. The orange
@@ -117,6 +117,11 @@ asset.onInitialize(function()
openspace.addSceneGraphNode(COBE)
openspace.addSceneGraphNode(WMAP)
openspace.addSceneGraphNode(Planck)
openspace.setGuiOrder(
"/Universe/Cosmic Microwave Background",
{ COBE.Identifier, WMAP.Identifier, Planck.Identifier }
)
end)
asset.onDeinitialize(function()
@@ -9,7 +9,7 @@ local speck = asset.resource({
Name = "Brown Dwarf Speck Files",
Type = "HttpSynchronization",
Identifier = "digitaluniverse_brown_dwarfs_speck",
Version = 1
Version = 2
})
@@ -36,6 +36,13 @@ local Object = {
ScaleExponent = 15.8,
MaxSize = 0.7,
EnableMaxSizeControl = true
},
Labels = {
File = speck .. "bd.label",
Color = { 0.6, 0.3, 0.4 },
Size = 13.75,
MinMaxSize = { 4, 30 },
Unit = "pc"
}
},
GUI = {
@@ -72,7 +79,7 @@ asset.export(Object)
asset.meta = {
Name = "Brown Dwarfs",
Author = "Brian Abbott, Zack Reeves, Jackie Faherty (AMNH)",
Author = "Brian Abbott, Zack Reeves, Ally Baldelli, Jackie Faherty (AMNH)",
Description = Object.GUI.Description,
License = "AMNH Digital Universe",
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
@@ -35,6 +35,7 @@ local Object = {
Scale = 10e17
}
},
Tag = { "du_grid" },
GUI = {
Name = "Constellation Boundaries",
Path = "/Milky Way/Constellations",
@@ -66,7 +66,7 @@ local DeepSkyObjectsImages = {
},
-- Use fixed orientation, and rotate planes based on orientation information in
-- the dataset
OrientationRenderOption = "Fixed Rotation",
Billboard = "Fixed Rotation",
UseOrientationData = true,
Unit = "pc",
SizeSettings = {
@@ -1,10 +1,15 @@
-- The only reason the SDSS asset is loaded at the top of this list is to start the
-- loading as soon as possible, as this asset is the most time intensive to initialize and
-- we want to minimize the waiting time on startup
asset.require("./sdss")
asset.require("./2dF")
asset.require("./2mass")
asset.require("./6dF")
asset.require("./abell")
asset.require("./allsky_hydrogenalpha")
asset.require("./allsky_visible")
asset.require("./alternatestarlabels")
asset.require("./backgroundradiation")
asset.require("./backgroundradiation_multiverse")
asset.require("./brown_dwarfs")
@@ -28,7 +33,6 @@ asset.require("./planetarynebulae")
asset.require("./pulsars")
asset.require("./quasars")
asset.require("./starlabels")
asset.require("./alternatestarlabels")
asset.require("./starorbits")
asset.require("./star_uncertainty")
asset.require("./stars")
@@ -9,7 +9,7 @@ local speck = asset.resource({
Name = "Exoplanets Speck Files",
Type = "HttpSynchronization",
Identifier = "digitaluniverse_exoplanets_speck",
Version = 4
Version = 5
})
@@ -38,7 +38,7 @@ local Object = {
}
},
GUI = {
Name = "Exoplanets",
Name = "Exoplanet Systems",
Path = "/Milky Way/Exoplanets",
Description = [[Extrasolar planets, or exoplanets, are a relatively new phenomenon in
astronomy - no observational evidence was available until 1995. To the eye,
@@ -67,7 +67,7 @@ asset.export(Object)
asset.meta = {
Name = "Exoplanets",
Description = Object.GUI.Description,
Author = "Brian Abbott, Zack Reeves (AMNH)",
Author = "Brian Abbott, Zack Reeves, Ally Baldelli (AMNH)",
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
License = "AMNH Digital Universe"
}
@@ -9,7 +9,7 @@ local speck = asset.resource({
Name = "Exoplanets Candidates Speck Files",
Type = "HttpSynchronization",
Identifier = "digitaluniverse_exoplanets_candidates_speck",
Version = 2
Version = 3
})
@@ -40,7 +40,7 @@ local Object = {
}
},
GUI = {
Name = "Exoplanetary Candidates",
Name = "Exoplanet Candidates",
Path = "/Milky Way/Exoplanets",
Description = [[The exoplanet candidate stars are likely hosts for exoplanets. These
are stars plucked from NASA's Kepler and TESS space telescopes. Further observations
@@ -69,7 +69,7 @@ asset.export(Object)
asset.meta = {
Name = "Exoplanetary Candidates",
Description = Object.GUI.Description,
Author = "Brian Abbott, Zack Reeves, Emily Rice, and Jason No (AMNH)",
Author = "Brian Abbott, Ally Baldelli, Zack Reeves, Emily Rice, and Jason No (AMNH)",
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
License = "AMNH Digital Universe"
}
+22 -1
View File
@@ -64,6 +64,7 @@ local RadioSphere = {
Color = { 0.3, 0.84, 1.0 },
LineWidth = 2.0
},
Tag = { "du_grid" },
GUI = {
Name = "Radio Sphere",
Path = "/Milky Way/Grids",
@@ -102,8 +103,10 @@ local EquatorialSphere = {
Opacity = 1.0,
Color = { 0.3, 0.3, 0.15 },
LineWidth = 2.0,
GridSegments = { 18, 24 },
LatSegments = 36,
LongSegments = 24,
},
Tag = { "du_grid" },
GUI = {
Name = "Equatorial Coordinates",
Path = "/Night Sky/Coordinate Systems/Equatorial",
@@ -131,6 +134,7 @@ local EquatorialSphereLabels = {
Unit = "pc",
TransformationMatrix = EquatorialTransformationMatrix
},
Tag = { "du_grid_labels" },
GUI = {
Name = "Equatorial Coordinates Labels",
Path = "/Night Sky/Coordinate Systems/Equatorial",
@@ -159,6 +163,7 @@ local EclipticSphere = {
Color = { 0.3, 0.15, 0.15 },
LineWidth = 2.0
},
Tag = { "du_grid" },
GUI = {
Name = "Ecliptic Coordinates",
Path = "/Night Sky/Coordinate Systems/Ecliptic",
@@ -186,6 +191,7 @@ local EclipticSphereLabels = {
Unit = "pc",
TransformationMatrix = EclipticTransformationMatrix
},
Tag = { "du_grid_labels" },
GUI = {
Name = "Ecliptic Coordinates Labels",
Path = "/Night Sky/Coordinate Systems/Ecliptic",
@@ -210,6 +216,7 @@ local GalacticSphere = {
Opacity = 1.0,
Color = { 0.05, 0.25, 0.25 }
},
Tag = { "du_grid" },
GUI = {
Name = "Galactic Coordinates",
Path = "/Night Sky/Coordinate Systems/Galactic",
@@ -235,6 +242,7 @@ local GalacticSphereLabels = {
Opacity = 0.65,
Unit = "pc"
},
Tag = { "du_grid_labels" },
GUI = {
Name = "Galactic Coordinates Labels",
Path = "/Night Sky/Coordinate Systems/Galactic",
@@ -268,6 +276,7 @@ local Plane1lh = {
Segments = { 20, 20 },
Size = { 2 * LightHour, 2 * LightHour }
},
Tag = { "du_grid" },
GUI = {
Name = "1-light-hour Grid",
Path = "/Solar System/Grids",
@@ -301,6 +310,7 @@ local Plane1ld = {
Segments = { 20, 20 },
Size = { 2 * LightDay, 2 * LightDay }
},
Tag = { "du_grid" },
GUI = {
Name = "1-light-day Grid",
Path = "/Solar System/Grids",
@@ -334,6 +344,7 @@ local Plane1lm = {
Segments = { 20, 20 },
Size = { 2 * LightMonth, 2 * LightMonth }
},
Tag = { "du_grid" },
GUI = {
Name = "1-light-month Grid",
Path = "/Solar System/Grids",
@@ -367,6 +378,7 @@ local Plane1ly = {
Segments = { 20, 20 },
Size = { 2 * LightYear, 2 * LightYear }
},
Tag = { "du_grid" },
GUI = {
Name = "1-light-year Grid",
Path = "/Solar System/Grids",
@@ -400,6 +412,7 @@ local Plane10ly = {
Segments = { 20, 20 },
Size = { 10 * 2 * LightYear, 10 * 2 * LightYear }
},
Tag = { "du_grid" },
GUI = {
Name = "10-light-year Grid",
Path = "/Milky Way/Grids",
@@ -433,6 +446,7 @@ local Plane100ly = {
Segments = { 20, 20 },
Size = { 100 * 2 * LightYear, 100 * 2 * LightYear }
},
Tag = { "du_grid" },
GUI = {
Name = "100-light-year Grid",
Path = "/Milky Way/Grids",
@@ -466,6 +480,7 @@ local Plane1kly = {
Segments = { 20, 20 },
Size = { 1000 * 2 * LightYear, 1000 * 2 * LightYear }
},
Tag = { "du_grid" },
GUI = {
Name = "1,000-light-year Grid",
Path = "/Milky Way/Grids",
@@ -499,6 +514,7 @@ local Plane10kly = {
Segments = { 20, 20 },
Size = { 10000 * 2 * LightYear, 10000 * 2 * LightYear }
},
Tag = { "du_grid" },
GUI = {
Name = "10,000-light-year Grid",
Path = "/Milky Way/Grids",
@@ -527,6 +543,7 @@ local Plane100kly = {
HighlightRate = { 5, 5 },
Size = { 100000 * 2 * LightYear, 100000 * 2 * LightYear }
},
Tag = { "du_grid" },
GUI = {
Name = "100,000-light-year Grid",
Path = "/Universe/Grids",
@@ -555,6 +572,7 @@ local Plane1Mly = {
HighlightRate = { 5, 5 },
Size = { 1E6 * 2 * LightYear, 1E6 * 2 * LightYear }
},
Tag = { "du_grid" },
GUI = {
Name = "1-million-light-year Grid",
Path = "/Universe/Grids",
@@ -583,6 +601,7 @@ local Plane10Mly = {
HighlightRate = { 5, 5 },
Size = { 10E6 * 2 * LightYear, 10E6 * 2 * LightYear }
},
Tag = { "du_grid" },
GUI = {
Name = "10-million-light-year Grid",
Path = "/Universe/Grids",
@@ -611,6 +630,7 @@ local Plane100Mly = {
HighlightRate = { 5, 5 },
Size = { 100E6 * 2 * LightYear, 100E6 * 2 * LightYear }
},
Tag = { "du_grid" },
GUI = {
Name = "100-million-light-year Grid",
Path = "/Universe/Grids",
@@ -639,6 +659,7 @@ local Plane20Gly = {
HighlightRate = { 5, 5 },
Size = { 20E9 * 2 * LightYear, 20E9 * 2 * LightYear }
},
Tag = { "du_grid" },
GUI = {
Name = "20-billion-light-year Grid",
Path = "/Universe/Grids",
@@ -24,7 +24,7 @@ local Object = {
},
-- Use fixed orientation, and rotate planes based on orientation information in
-- the dataset
OrientationRenderOption = "Fixed Rotation",
Billboard = "Fixed Rotation",
UseOrientationData = true,
Unit = "pc",
Fading = {
@@ -38,7 +38,7 @@ local Object = {
},
},
GUI = {
Name = "Milky Way Galaxy Image",
Name = "Milky Way Image",
Path = "/Milky Way/Galaxy",
Description = [[The exterior view of the Milky Way is represented here by a
two-dimensional image. The image is that of NGC 1232, a galaxy thought to resemble
@@ -25,7 +25,7 @@ local Object = {
},
-- Use fixed orientation, and rotate planes based on orientation information in
-- the dataset
OrientationRenderOption = "Fixed Rotation",
Billboard = "Fixed Rotation",
UseOrientationData = true,
Unit = "pc",
Fading = {
@@ -39,7 +39,7 @@ local Object = {
},
},
GUI = {
Name = "Milky Way Arms Labels",
Name = "Milky Way Arm Labels",
Path = "/Milky Way/Galaxy",
Description = [[This is an image that contains labels for the Milky Way's spiral
arms. We label them in this manner--"hard-coding" the labels into an image rather
@@ -39,7 +39,7 @@ local Object = {
},
GUI = {
Name = "Oort Sphere",
Path = "/Solar System/Comets",
Path = "/Solar System/Comets/Oort Cloud",
Description = [[The Oort cloud is a region of space surrounding the Sun where comets
are believed to originate. It is believed to extend from 20,000-100,000 Astronomical
Units (AU), with its greatest concentration around 50,000 AU (1 AU is the average
+1 -1
View File
@@ -43,7 +43,7 @@ local Object = {
}
},
GUI = {
Name = "Sloan Digital Sky Survey",
Name = "Sloan Galaxies",
Path = "/Universe/Deep Sky Surveys",
Description = [[The Sloan Digital Sky Survey (SDSS) is an ambitious project to image
about 35% of the sky, deep into the universe. The SDSS galaxies form triangular
@@ -86,7 +86,7 @@ local TullyGalaxiesImages = {
TransformationMatrix = transforms.Supergalactic,
-- Use fixed orientation, and rotate planes based on orientation information in
-- the dataset
OrientationRenderOption = "Fixed Rotation",
Billboard = "Fixed Rotation",
UseOrientationData = true,
Unit = "Mpc",
Fading = {
@@ -102,7 +102,7 @@ local TullyGalaxiesImages = {
}
},
GUI = {
Name = "Tully Galaxies Images",
Name = "Tully Galaxy Images",
Path = "/Universe/Nearby Surveys",
Description = [[Each Tully galaxy is represented by an image that represents its
morphological type (spiral, elliptical, etc.). Most of these come from The Galaxy
@@ -89,7 +89,7 @@ local function createConstellations(baseIdentifier, guiPath, constellationfile)
Opacity = 0.1,
DimInAtmosphere = true
},
Tag = { "ImageConstellation", group, "daytime_hidden" },
Tag = { "image_constellation", "zodiac_" .. group, "daytime_hidden" },
GUI = {
Name = name .. " Image",
Path = "/Milky Way/Constellations/" .. guiPath,
@@ -14,7 +14,7 @@ local KiloParsec = 3.086E19
local MilkyWayVolume = {
Identifier = "MilkyWayVolume",
Parent = transforms.SolarSystemBarycenter.Identifier,
-- No parent; this node is attached to the scene graph root
Transform = {
Translation = {
Type = "StaticTranslation",
@@ -1,4 +1,3 @@
local propertyHelper = asset.require("util/property_helper")
local sunTransforms = asset.require("scene/solarsystem/sun/transforms")
local sunAsset = asset.require("scene/solarsystem/sun/sun")
@@ -1,5 +1,4 @@
local heliosphereTransforms = asset.require("scene/solarsystem/sun/transforms_heliosphere")
local propertyHelper = asset.require("util/property_helper")
local rot = asset.require("./carrington_to_heeq_rotation")
@@ -1,5 +1,4 @@
local heliosphereTransforms = asset.require("scene/solarsystem/sun/transforms_heliosphere")
local propertyHelper = asset.require("util/property_helper")
local rot = asset.require("./carrington_to_heeq_rotation")
@@ -1,4 +1,3 @@
local propertyHelper = asset.require("util/property_helper")
local transforms = asset.require("scene/solarsystem/sun/transforms_heliosphere")
local rot = asset.require("./carrington_to_heeq_rotation")
@@ -261,3 +261,14 @@ asset.export(Apollo11LemDescentModel)
asset.export(Apollo11LemLandedModel)
asset.export(Apollo11MoonTrail)
asset.export(Apollo11LemTrail)
asset.meta = {
Name = "Apollo 11",
Description = [[A meta asset that will include all of the other assets to show the
Apollo 11 launch, orbit, and landing sequence.]],
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license"
}
@@ -34,3 +34,14 @@ end)
asset.export("ID", ID)
asset.export("Frame", Frame)
asset.meta = {
Name = "Apollo 11 Kernel",
Description = [[This asset downloads and provides the kernels needed for the Apollo 11
launch, trans-lunar injection, and moon orbit.]],
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license"
}

Some files were not shown because too many files have changed in this diff Show More