Merge branch 'master' into feature/horizons-framework

This commit is contained in:
Malin E
2022-04-08 17:16:50 +02:00
91 changed files with 830 additions and 990 deletions
+9 -6
View File
@@ -1,15 +1,15 @@
# Core Team
Alexander Bock
Emma Broman
Emil Axelsson
Gene Payne
Kalle Bladin
Jonathas Costa
Gene Payne
Emma Broman
Jonas Strandstedt
Micah Acinapura
Michal Marcinkowski
Malin Ejdbo
Elon Olsson
Micah Acinapura
Jonas Strandstedt
Michal Marcinkowski
Joakim Kilby
Lovisa Hassler
Mikael Petterson
@@ -23,6 +23,8 @@ Erik Broberg
Jonathan Bosson
Michael Nilsson
Jonathan Franzen
ChristianAdamsson
Emilie Ho
Karin Reidarman
Hans-Christian Helltegen
Anton Arbring
@@ -39,15 +41,16 @@ Michael Sjöström
Michael Novén
Christoffer Särevall
# Community Support
Anteige
arfon
DavidLaidlaw
ethanejohnsons
johnriedel
mik3caprio
mingenuity
nbartzokas
nealmcb
noahdasanaike
PTrottier
sa5bke
Vendored
+6
View File
@@ -6,6 +6,12 @@ library('sharedSpace'); // jenkins-pipeline-lib
def url = 'https://github.com/OpenSpace/OpenSpace';
def branch = env.BRANCH_NAME;
// The CHANGE_BRANCH only exists if we are building a PR branch in which case it returns
// the original branch
if (env.CHANGE_BRANCH) {
branch = env.CHANGE_BRANCH;
}
@NonCPS
def readDir() {
def dirsl = [];
+1 -1
View File
@@ -34,7 +34,7 @@ OpenSpace requires at least support for [OpenGL](https://www.opengl.org/) versio
![Image](https://github.com/OpenSpace/openspace.github.io/raw/master/assets/images/display-systems.jpg)
# Getting Started
This repository contains the source code and example profiles for OpenSpace, but does not contain any data. To build and install the application, please check out the [OpenSpace Wiki](http://wiki.openspaceproject.com/). Here, you will find two pages, a [build instruction](http://wiki.openspaceproject.com/docs/developers/compiling/general) for all operating systems and then additional instructions for [Windows](http://wiki.openspaceproject.com/docs/developers/compiling/windows), [Linux (Ubuntu)](http://wiki.openspaceproject.com/docs/developers/compiling/ubuntu), and [MacOS](http://wiki.openspaceproject.com/docs/developers/compiling/macos).
This repository contains the source code and example profiles for OpenSpace, but does not contain any data. To build and install the application, please check out the [GitHub Wiki](https://github.com/OpenSpace/OpenSpace/wiki). Here, you will find two pages, a [build instruction](https://github.com/OpenSpace/OpenSpace/wiki/Compiling) for all operating systems and then additional instructions for [Windows](https://github.com/OpenSpace/OpenSpace/wiki/Compiling-Windows), [Linux (Ubuntu)](https://github.com/OpenSpace/OpenSpace/wiki/Compiling-Ubuntu), and [MacOS](https://github.com/OpenSpace/OpenSpace/wiki/Compiling-MacOS). Please note that the Apple Silicon series of chips do not support OpenGL natively and Metal 2 does not support `double` precision accuracy (see [here](https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf) Section 2.1), therefore only the Intel processors for MacOS are supported and maintained.
Requirements for compiling are:
- CMake version 3.10 or above
@@ -58,6 +58,8 @@ private:
void actionSaved();
void clearActionFields();
void actionRejected();
void chooseScripts();
void appendScriptsToTextfield(std::string scripts);
openspace::Profile::Keybinding* selectedKeybinding();
void keybindingAdd();
@@ -80,6 +82,7 @@ private:
QLineEdit* guiPath = nullptr;
QLineEdit* documentation = nullptr;
QCheckBox* isLocal = nullptr;
QPushButton* chooseScripts = nullptr;
QTextEdit* script = nullptr;
QPushButton* addButton = nullptr;
QPushButton* removeButton = nullptr;
@@ -40,6 +40,7 @@
#include <QPushButton>
#include <QTextBrowser>
#include <QVector>
#include <memory>
#include <vector>
class DisplayWindowUnion : public QWidget {
@@ -25,6 +25,7 @@
#include "profile/actiondialog.h"
#include "profile/line.h"
#include "profile/scriptlogdialog.h"
#include <openspace/util/keys.h>
#include <ghoul/fmt.h>
#include <ghoul/misc/assert.h>
@@ -81,7 +82,7 @@ void ActionDialog::createWidgets() {
// | | Name | [oooooooooooo] | Row 2
// | | GUI Path | [oooooooooooo] | Row 3
// | | Documentation | [oooooooooooo] | Row 4
// | | Is Local | [] | Row 5
// | | Is Local | [] [choosescr] | Row 5
// | | Script | [oooooooooooo] | Row 6
// *----------------------*---------------*----------------*
// | [+] [-] | | [Save] [Cancel]| Row 7
@@ -205,6 +206,17 @@ void ActionDialog::createActionWidgets(QGridLayout* layout) {
_actionWidgets.isLocal->setEnabled(false);
layout->addWidget(_actionWidgets.isLocal, 5, 2);
_actionWidgets.chooseScripts = new QPushButton("Choose Scripts");
_actionWidgets.chooseScripts->setToolTip(
"Press this button to choose scripts for your action from the logs/scriptlog.txt"
);
connect(
_actionWidgets.chooseScripts, &QPushButton::clicked,
this, &ActionDialog::chooseScripts
);
_actionWidgets.chooseScripts->setEnabled(false);
layout->addWidget(_actionWidgets.chooseScripts, 5, 2, Qt::AlignRight);
layout->addWidget(new QLabel("Script"), 6, 1);
_actionWidgets.script = new QTextEdit;
_actionWidgets.script->setToolTip(
@@ -499,6 +511,7 @@ void ActionDialog::actionSelected() {
_actionWidgets.documentation->setEnabled(true);
_actionWidgets.isLocal->setChecked(action->isLocal);
_actionWidgets.isLocal->setEnabled(true);
_actionWidgets.chooseScripts->setEnabled(true);
_actionWidgets.script->setText(QString::fromStdString(action->script));
_actionWidgets.script->setEnabled(true);
_actionWidgets.addButton->setEnabled(false);
@@ -589,6 +602,7 @@ void ActionDialog::clearActionFields() {
_actionWidgets.documentation->setEnabled(false);
_actionWidgets.isLocal->setChecked(false);
_actionWidgets.isLocal->setEnabled(false);
_actionWidgets.chooseScripts->setEnabled(false);
_actionWidgets.script->clear();
_actionWidgets.script->setEnabled(false);
_actionWidgets.saveButtons->setEnabled(false);
@@ -604,6 +618,16 @@ void ActionDialog::actionRejected() {
clearActionFields();
}
void ActionDialog::chooseScripts() {
ScriptlogDialog d(this);
connect(&d, &ScriptlogDialog::scriptsSelected, this, &ActionDialog::appendScriptsToTextfield);
d.exec();
}
void ActionDialog::appendScriptsToTextfield(std::string scripts) {
_actionWidgets.script->append(QString::fromStdString(std::move(scripts)));
}
Profile::Keybinding* ActionDialog::selectedKeybinding() {
QListWidgetItem* item = _keybindingWidgets.list->currentItem();
const int idx = _keybindingWidgets.list->row(item);
@@ -71,13 +71,13 @@ CameraDialog::CameraDialog(QWidget* parent,
_navState.anchor->setText(QString::fromStdString(nav.anchor));
_navState.aim->setText(QString::fromStdString(*nav.aim));
_navState.refFrame->setText(QString::fromStdString(nav.referenceFrame));
_navState.positionX->setText(QString::number(nav.position.x));
_navState.positionY->setText(QString::number(nav.position.y));
_navState.positionZ->setText(QString::number(nav.position.z));
_navState.positionX->setText(QString::number(nav.position.x, 'g', 17));
_navState.positionY->setText(QString::number(nav.position.y, 'g', 17));
_navState.positionZ->setText(QString::number(nav.position.z, 'g', 17));
if (nav.up.has_value()) {
_navState.upX->setText(QString::number(nav.up.value().x));
_navState.upY->setText(QString::number(nav.up.value().y));
_navState.upZ->setText(QString::number(nav.up.value().z));
_navState.upX->setText(QString::number(nav.up.value().x, 'g', 17));
_navState.upY->setText(QString::number(nav.up.value().y, 'g', 17));
_navState.upZ->setText(QString::number(nav.up.value().z, 'g', 17));
}
else {
_navState.upX->clear();
@@ -85,13 +85,13 @@ CameraDialog::CameraDialog(QWidget* parent,
_navState.upZ->clear();
}
if (nav.yaw.has_value()) {
_navState.yaw->setText(QString::number(*nav.yaw));
_navState.yaw->setText(QString::number(*nav.yaw, 'g', 17));
}
else {
_navState.yaw->clear();
}
if (nav.pitch.has_value()) {
_navState.pitch->setText(QString::number(*nav.pitch));
_navState.pitch->setText(QString::number(*nav.pitch, 'g', 17));
}
else {
_navState.pitch->clear();
@@ -101,10 +101,10 @@ CameraDialog::CameraDialog(QWidget* parent,
[this](const openspace::Profile::CameraGoToGeo& geo) {
_tabWidget->setCurrentIndex(CameraTypeGeo);
_geoState.anchor->setText(QString::fromStdString(geo.anchor));
_geoState.latitude->setText(QString::number(geo.latitude));
_geoState.longitude->setText(QString::number(geo.longitude));
_geoState.latitude->setText(QString::number(geo.latitude, 'g', 17));
_geoState.longitude->setText(QString::number(geo.longitude, 'g', 17));
if (geo.altitude.has_value()) {
_geoState.altitude->setText(QString::number(*geo.altitude));
_geoState.altitude->setText(QString::number(*geo.altitude, 'g', 17));
}
else {
_geoState.altitude->clear();
+32 -1
View File
@@ -28,6 +28,7 @@
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/joystickinputstate.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/keys.h>
#include <ghoul/ghoul.h>
#include <ghoul/filesystem/filesystem.h>
@@ -810,6 +811,36 @@ void setSgctDelegateFunctions() {
vec2 scale = currentWindow->scale();
return glm::vec2(scale.x, scale.y);
};
sgctDelegate.osDpiScaling = []() {
ZoneScoped
// Detect which DPI scaling to use
// 1. If there is a GUI window, use the GUI window's content scale value
const Window* dpiWindow = nullptr;
for (const std::unique_ptr<Window>& window : Engine::instance().windows()) {
if (window->hasTag("GUI")) {
dpiWindow = window.get();
break;
}
}
// 2. If there isn't a GUI window, use the first window's value
if (!dpiWindow) {
dpiWindow = Engine::instance().windows().front().get();
}
glm::vec2 scale = glm::vec2(1.f, 1.f);
glfwGetWindowContentScale(dpiWindow->windowHandle(), &scale.x, &scale.y);
if (scale.x != scale.y) {
LWARNING(fmt::format(
"Non-square window scaling detected ({0}x{1}), using {0}x{0} instead",
scale.x, scale.y
));
}
return scale.x;
};
sgctDelegate.hasGuiWindow = []() {
ZoneScoped
@@ -1319,7 +1350,7 @@ int main(int argc, char* argv[]) {
#endif // __APPLE__
// Do not print message if slaves are waiting for the master
// Do not print message if clients are waiting for the master
// Only timeout after 15 minutes
Engine::instance().setSyncParameters(false, 15.f * 60.f);
-64
View File
@@ -1,64 +0,0 @@
##########################################################################################
# #
# OpenSpace #
# #
# Copyright (c) 2014-2022 #
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy of this #
# software and associated documentation files (the "Software"), to deal in the Software #
# without restriction, including without limitation the rights to use, copy, modify, #
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to #
# permit persons to whom the Software is furnished to do so, subject to the following #
# conditions: #
# #
# The above copyright notice and this permission notice shall be included in all copies #
# or substantial portions of the Software. #
# #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, #
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A #
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT #
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF #
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE #
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #
##########################################################################################
include(${OPENSPACE_CMAKE_EXT_DIR}/application_definition.cmake)
set_source_files_properties(
${CMAKE_CURRENT_SOURCE_DIR}/openspace.icns
PROPERTIES MACOSX_PACKAGE_LOCATION "Resources"
)
set(MACOSX_BUNDLE_ICON_FILE openspace.icns)
create_new_application(
Wormhole MACOSX_BUNDLE
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/openspace.rc
${CMAKE_CURRENT_SOURCE_DIR}/openspace.icns
)
target_link_libraries(Wormhole PRIVATE openspace-core openspace-module-collection)
# Web Browser and Web gui
# Why not put these in the module's path? Because they do not have access to the
# target as of July 2017, which is needed.
if (OPENSPACE_MODULE_WEBBROWSER AND CEF_ROOT)
# wanted by CEF
set(CMAKE_BUILD_TYPE Debug CACHE STRING "CMAKE_BUILD_TYPE")
set(PROJECT_ARCH "x86_64")
if (WIN32)
set(RESOURCE_FILE ${OPENSPACE_APPS_DIR}/OpenSpace/openspace.rc)
endif ()
# Add the CEF binary distribution's cmake/ directory to the module path and
# find CEF to initialize it properly.
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${WEBBROWSER_MODULE_PATH}/cmake")
include(webbrowser_helpers)
set_cef_targets("${CEF_ROOT}" Wormhole)
run_cef_platform_config("${CEF_ROOT}" "${CEF_TARGET}" "${WEBBROWSER_MODULE_PATH}")
elseif (OPENSPACE_MODULE_WEBBROWSER)
message(WARNING "Web configured to be included, but no CEF_ROOT was found, please try configuring CMake again.")
endif ()
-1
View File
@@ -1 +0,0 @@
set(DEFAULT_APPLICATION ON)
-133
View File
@@ -1,133 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/network/parallelserver.h>
#include <ghoul/fmt.h>
#include <ghoul/cmdparser/commandlineparser.h>
#include <ghoul/cmdparser/singlecommand.h>
#include <ghoul/logging/logmanager.h>
#include <iomanip>
namespace {
constexpr const char*_loggerCat = "Wormhole";
} // namespace
int main(int argc, char** argv) {
using namespace openspace;
using namespace ghoul::cmdparser;
std::vector<std::string> arguments(argv, argv + argc);
CommandlineParser commandlineParser(
"Wormhole",
CommandlineParser::AllowUnknownCommands::Yes
);
struct {
std::string port;
std::string password;
std::string changeHostPassword;
} settings;
commandlineParser.addCommand(
std::make_unique<ghoul::cmdparser::SingleCommand<std::string>>(
settings.port,
"--port",
"-p",
"Sets the port to listen on"
)
);
commandlineParser.addCommand(
std::make_unique<ghoul::cmdparser::SingleCommand<std::string>>(
settings.password,
"--password",
"-l",
"Sets the password to use"
)
);
commandlineParser.addCommand(
std::make_unique<ghoul::cmdparser::SingleCommand<std::string>>(
settings.changeHostPassword,
"--hostpassword",
"-h",
"Sets the host password to use"
)
);
ghoul::logging::LogManager::initialize(
ghoul::logging::LogLevel::Debug,
ghoul::logging::LogManager::ImmediateFlush::Yes
);
commandlineParser.setCommandLine(arguments);
commandlineParser.execute();
if (settings.password.empty()) {
std::stringstream defaultPassword;
defaultPassword << std::hex << std::setfill('0') << std::setw(6) <<
(std::hash<size_t>{}(
std::chrono::system_clock::now().time_since_epoch().count()
) % 0xffffff);
settings.password = defaultPassword.str();
}
if (settings.changeHostPassword.empty()) {
std::stringstream defaultChangeHostPassword;
defaultChangeHostPassword << std::hex << std::setfill('0') << std::setw(6) <<
(std::hash<size_t>{}(
std::chrono::system_clock::now().time_since_epoch().count() + 1
) % 0xffffff);
settings.changeHostPassword = defaultChangeHostPassword.str();
}
LINFO(fmt::format("Connection password: {}", settings.password));
LINFO(fmt::format("Host password: {}", settings.changeHostPassword));
int port = 25001;
if (!settings.port.empty()) {
try {
port = std::stoi(settings.port);
}
catch (const std::invalid_argument&) {
LERROR(fmt::format("Invalid port: {}", settings.port));
}
}
ParallelServer server;
server.start(port, settings.password, settings.changeHostPassword);
server.setDefaultHostAddress("127.0.0.1");
LINFO(fmt::format("Server listening to port {}", port));
while (std::cin.get() != 'q') {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
server.stop();
LINFO("Server stopped");
return 0;
}
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

-1
View File
@@ -1 +0,0 @@
IDI_ICON1 ICON DISCARDABLE "openspace.ico"
+9 -5
View File
@@ -32,7 +32,11 @@ local toggle_trail = {
visibility = not openspace.getPropertyValue("Scene." .. trail .. ".Renderable.Enabled")
end
openspace.setPropertyValueSingle("Scene." .. trail .. ".Renderable.Enabled", visibility)
if visibility then
openspace.setPropertyValueSingle("Scene." .. trail .. ".Renderable.Fade", 1.0, 1.0)
else
openspace.setPropertyValueSingle("Scene." .. trail .. ".Renderable.Fade", 0.0, 1.0)
end
]],
Documentation = [[Toggles the visibility of the associated trail of a scene graph node.
This action takes optional arguments to 1) determine which trail to hide (as the
@@ -54,9 +58,9 @@ local hide_trail = {
end
if openspace.hasSceneGraphNode(node .. "Trail") then
openspace.setPropertyValue("Scene." .. node .. "Trail.Renderable.Enabled", false)
openspace.setPropertyValueSingle("Scene." .. node .. "Trail.Renderable.Fade", 0.0, 1.0)
elseif openspace.hasSceneGraphNode(node .. "_trail") then
openspace.setPropertyValue("Scene." .. node .. "_trail.Renderable.Enabled", false)
openspace.setPropertyValueSingle("Scene." .. node .. "_trail.Renderable.Fade", 0.0, 1.0)
end
]],
Documentation = [[Hides the associated trail of a scene graph node. This action takes an
@@ -79,9 +83,9 @@ local show_trail = {
end
if openspace.hasSceneGraphNode(node .. "Trail") then
openspace.setPropertyValue("Scene." .. node .. "Trail.Renderable.Enabled", true)
openspace.setPropertyValueSingle("Scene." .. node .. "Trail.Renderable.Fade", 1.0, 1.0)
elseif openspace.hasSceneGraphNode(node .. "_trail") then
openspace.setPropertyValue("Scene." .. node .. "_trail.Renderable.Enabled", true)
openspace.setPropertyValueSingle("Scene." .. node .. "_trail.Renderable.Fade", 1.0, 1.0)
end
]],
Documentation = [[Shows the associated trail of a scene graph node. This action takes an
+4 -1
View File
@@ -5,13 +5,16 @@ local propertyHelper = asset.require("util/property_helper")
-- Specifying which other assets should be loaded in this scene
asset.require("spice/base")
-- Load default key bindings applicable to most scenes
asset.require("dashboard/default_dashboard")
-- Load default key bindings applicable to most scenes
asset.require("util/default_keybindings")
-- Load web gui
local webGui = asset.require("util/webgui")
-- Scale the different UI components based on the operating system's DPI scaling value
asset.require("util/dpiscaling")
local toggle_trails = {
Identifier = "os_default.toggle_trails",
Name = "Toggle Trails",
+65
View File
@@ -0,0 +1,65 @@
local toggle_sun = {
Identifier = "os.toggle_sun",
Name = "Toggle Sun",
Command = [[
if not is_declared("args") then
openspace.printError("Cannot execute 'os.toggle_sun' manually")
return
end
if not openspace.getPropertyValue("Scene.Sun.Renderable.Enabled") then
openspace.setPropertyValueSingle("Scene.Sun.Renderable.Enabled", true)
end
if args.Transition == "Approaching" then
openspace.setPropertyValueSingle("Scene.SunGlare.Renderable.Fade", 0.0, 1.0)
openspace.setPropertyValueSingle("Scene.Sun.Renderable.Fade", 1.0, 1.0)
else -- "Exiting"
openspace.setPropertyValueSingle("Scene.SunGlare.Renderable.Fade", 1.0, 1.0)
openspace.setPropertyValueSingle("Scene.Sun.Renderable.Fade", 0.0, 1.0)
end
]],
Documentation = [[Toggles the visibility of the Sun glare and the Sun globe when the
camera is approaching either so that from far away the Sun Glare is rendered and when
close up, the globe is rendered instead.]],
GuiPath = "/Sun",
IsLocal = false
}
asset.onInitialize(function()
openspace.action.registerAction(toggle_sun)
openspace.event.registerEventAction(
"CameraFocusTransition",
toggle_sun.Identifier,
{ Node = "Sun", Transition = "Approaching" }
)
openspace.event.registerEventAction(
"CameraFocusTransition",
toggle_sun.Identifier,
{ Node = "Sun", Transition = "Exiting" }
)
end)
asset.onDeinitialize(function()
openspace.event.unregisterEventAction(
"CameraFocusTransition",
toggle_sun.Identifier,
{ Node = "Sun", Transition = "Exiting" }
)
openspace.event.unregisterEventAction(
"CameraFocusTransition",
toggle_sun.Identifier,
{ Node = "Sun", Transition = "Approaching" }
)
openspace.action.removeAction(toggle_sun)
end)
asset.meta = {
Name = "Actions - Toggle current Trails",
Version = "1.0",
Description = [[ Asset providing actions to toggle trails]],
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license"
}
+4 -4
View File
@@ -5,12 +5,12 @@ asset.onInitialize(function()
"CameraFocusTransition",
action.show_trail,
{ Transition = "Exiting" }
);
)
openspace.event.registerEventAction(
"CameraFocusTransition",
action.hide_trail,
{ Transition = "Approaching" }
);
)
end)
asset.onDeinitialize(function()
@@ -18,10 +18,10 @@ asset.onDeinitialize(function()
"CameraFocusTransition",
action.show_trail,
{ Transition = "Exiting" }
);
)
openspace.event.unregisterEventAction(
"CameraFocusTransition",
action.hide_trail,
{ Transition = "Approaching" }
);
)
end)
@@ -0,0 +1,23 @@
local shared = asset.require("util/tle_helper")
local group = {
Title = "Starlink",
Url = "http://www.celestrak.com/NORAD/elements/starlink.txt",
TrailColor = { 0.65, 0.55, 0.55 },
Description = [[LEO satellite constellation launched by SpaceX to provide
broadband internet access.]]
}
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
shared.registerSatelliteGroupObjects(asset, group, tle, true)
asset.meta = {
Name = "Satellites Communications - Starlink",
Version = "1.0",
Description = [[ Satellites asset for Communications - Starlink. Data from
Celestrak]],
Author = "OpenSpace Team",
URL = "https://celestrak.com/NORAD/elements/",
License = "Celestrak"
}
@@ -0,0 +1,21 @@
local shared = asset.require("util/tle_helper")
local group = {
Title = "Active",
Url = "http://www.celestrak.com/NORAD/elements/active.txt",
TrailColor = { 0.45, 0.25, 0.45 },
Description = [[Satellites that employ active communication.]]
}
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
shared.registerSatelliteGroupObjects(asset, group, tle, true)
asset.meta = {
Name = "Satellites Active",
Version = "1.0",
Description = [[ Satellites that employ active communication. Data from Celestrak]],
Author = "OpenSpace Team",
URL = "https://celestrak.com/NORAD/elements/",
License = "Celestrak"
}
@@ -11,6 +11,7 @@ asset.require("./communications/other_comm")
asset.require("./communications/gorizont")
asset.require("./communications/raduga")
asset.require("./communications/molniya")
asset.require("./communications/starlink")
asset.meta = {
@@ -2,6 +2,7 @@ asset.require("./misc/military")
asset.require("./misc/radar")
asset.require("./misc/cubesats")
asset.require("./misc/other")
asset.require("./misc/active")
asset.meta = {
@@ -12,6 +12,7 @@ local Sun = {
Layers = {},
PerformShading = false
},
ApproachFactor = 15.0,
GUI = {
Name = "Sun",
Path = "/Solar System/Sun",
+188
View File
@@ -0,0 +1,188 @@
openspace.printWarning("Warning asset_helper has been deprecated and will be removed in future verions");
local tableLength = function(table)
local count = 0
for _ in pairs(table) do count = count + 1 end
return count
end
local registerSpiceKernels = function (spiceAsset, kernels)
spiceAsset.onInitialize(function ()
for i, kernel in ipairs(kernels) do
openspace.spice.loadKernel(kernel)
end
end)
spiceAsset.onDeinitialize(function ()
for i = #kernels, 1, -1 do
local kernel = kernels[i]
openspace.spice.unloadKernel(kernel)
end
end)
end
local registerSceneGraphNodes = function (sceneAsset, nodes, override)
override = override or false
if not override then
if tableLength(nodes) == 0 then
openspace.printWarning(sceneAsset.filePath .. ": Register function was called with an empty node list. Pass 'true' as third argument to silence this warning.")
return
end
end
sceneAsset.onInitialize(function ()
for i, node in ipairs(nodes) do
openspace.addSceneGraphNode(node)
end
end)
sceneAsset.onDeinitialize(function ()
for i = #nodes, 1, -1 do
node = nodes[i]
openspace.removeSceneGraphNode(node.Identifier)
end
end)
end
local registerScreenSpaceRenderables = function (sceneAsset, renderables, override)
override = override or false
if not override then
if tableLength(renderables) == 0 then
openspace.printWarning(sceneAsset.filePath .. ": Register function was called with an empty node list. Pass 'true' as third argument to silence this warning.")
return
end
end
sceneAsset.onInitialize(function ()
for i, node in ipairs(renderables) do
openspace.addScreenSpaceRenderable(node)
end
end)
sceneAsset.onDeinitialize(function ()
for i = #renderables, 1, -1 do
renderable = renderables[i]
openspace.removeScreenSpaceRenderable(renderable.Identifier)
end
end)
end
local registerDashboardItems = function (dashboardAsset, items)
dashboardAsset.onInitialize(
function ()
for i, item in ipairs(items) do
openspace.dashboard.addDashboardItem(item)
end
end
)
dashboardAsset.onDeinitialize(function ()
for i = #items, 1, -1 do
local item = items[i]
openspace.dashboard.removeDashboardItem(item.Identifier)
end
end)
end
local registerSceneGraphNodesAndExport = function (sceneAsset, nodes, override)
override = override or false
if not override then
if tableLength(nodes) == 0 then
openspace.printWarning(sceneAsset.filePath .. ": Register function was called with an empty node list. Pass 'true' as third argument to silence this warning.")
return
end
end
for i, node in ipairs(nodes) do
if not node.Identifier then
openspace.printError("Could not load asset as Identifier was missing")
end
end
sceneAsset.onInitialize(function ()
for i, node in ipairs(nodes) do
openspace.addSceneGraphNode(node)
end
end)
sceneAsset.onDeinitialize(function ()
for i = #nodes, 1, -1 do
local node = nodes[i]
openspace.removeSceneGraphNode(node.Identifier)
end
end)
for i, node in ipairs(nodes) do
sceneAsset.export(node.Identifier, node)
end
end
local requireAll = function (sceneAsset, directory)
function string.ends(String,End)
return End=='' or string.sub(String,-string.len(End))==End
end
local result = {}
local files = openspace.walkDirectoryFiles(sceneAsset.localResource('') .. directory, true)
for _, file in pairs(files) do
if file:ends('.asset') then
openspace.printDebug("Requiring: " .. file:sub(file:find(directory), -7))
local exports = sceneAsset.require(file:sub(1, -7))
table.insert(result, exports)
end
end
return result
end
local getDefaultLightSources = function (solarSystemBarycenterIdentifier)
local sourceList = {
{
Type = "SceneGraphLightSource",
Identifier = "Sun",
Node = solarSystemBarycenterIdentifier,
Intensity = 1.0
},
{
Identifier = "Camera",
Type = "CameraLightSource",
Intensity = 0.5
}
}
return sourceList
end
local createModelPart = function (parent, sunLightSourceNode, models, geometry, texture, performShading)
local lightSources = {}
if performShading then
lightSources[1] = {
Type = "SceneGraphLightSource",
Identifier = "Sun",
Node = sunLightSourceNode,
Intensity = 1.0
}
end
return {
Identifier = parent .. "-" .. geometry,
Parent = parent,
Renderable = {
Type = "RenderableModel",
GeometryFile = models .. "/" .. geometry .. ".obj",
LightSources = lightSources,
PerformShading = performShading,
DisableFaceCulling = true
},
GUI = {
Hidden = true
}
}
end
asset.export("registerSceneGraphNodes", registerSceneGraphNodes)
asset.export("registerSceneGraphNodesAndExport", registerSceneGraphNodesAndExport)
asset.export("registerScreenSpaceRenderables", registerScreenSpaceRenderables)
asset.export("registerSpiceKernels", registerSpiceKernels)
asset.export("registerDashboardItems", registerDashboardItems)
asset.export("requireAll", requireAll)
asset.export("getDefaultLightSources", getDefaultLightSources)
asset.export("createModelPart", createModelPart)
+37
View File
@@ -0,0 +1,37 @@
asset.onInitialize(function ()
local scale = openspace.dpiScaling()
openspace.printInfo("Setting the DPI scaling factor to " .. tostring(scale))
if openspace.modules.isLoaded("CefWebGui") then
openspace.setPropertyValueSingle(
"Modules.CefWebGui.GuiScale",
openspace.getPropertyValue("Modules.CefWebGui.GuiScale") * scale
)
end
local dashboards = openspace.getProperty("Dashboard.*.FontSize");
for _, v in ipairs(dashboards) do
openspace.setPropertyValueSingle(
v,
openspace.getPropertyValue(v) * scale
)
end
local offset = openspace.getPropertyValue("Dashboard.StartPositionOffset")
openspace.setPropertyValueSingle(
"Dashboard.StartPositionOffset",
{ offset[1] * scale, offset[2] * scale }
)
end)
asset.meta = {
Name = "DPI Scaling",
Version = "1.0",
Description = [[ Retrieves the DPI scaling from the operating system and applies it to
a few selected places to make them scale better on "large resolution but small size"
monitors ]],
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license"
}
+2 -1
View File
@@ -27,6 +27,7 @@
],
"assets": [
"base",
"events/toggle_sun",
"scene/solarsystem/planets/earth/earth",
"scene/solarsystem/planets/earth/satellites/satellites"
],
@@ -104,4 +105,4 @@
"major": 1,
"minor": 1
}
}
}
+2 -1
View File
@@ -35,6 +35,7 @@
],
"assets": [
"base",
"events/toggle_sun",
"scene/solarsystem/planets/earth/earth",
"scene/solarsystem/planets/earth/satellites/satellites",
"scene/solarsystem/planets/jupiter/major_moons",
@@ -130,4 +131,4 @@
"major": 1,
"minor": 1
}
}
}
+1 -1
View File
@@ -57,7 +57,7 @@ public:
/**
* Decodes the <code>SyncBuffer</code> into the added Syncables.
* This method is only called on the SGCT slave nodes
* This method is only called on the SGCT client nodes
*/
void decodeSyncables(std::vector<std::byte> data);
@@ -64,6 +64,8 @@ struct WindowDelegate {
glm::vec2 (*dpiScaling)() = []() { return glm::vec2(1.f); };
float (*osDpiScaling)() = []() { return 1.f; };
bool (*hasGuiWindow)() = []() { return false; };
bool (*isGuiWindow)() = []() { return false; };
+7
View File
@@ -87,6 +87,13 @@ public:
*/
bool hasReachedEnd() const;
/**
* Compute the interpolated camera pose at a certain distance along a *linear*
* path. Note that the linear path is a special case, to avoid risks of precision
* problems for long paths
*/
CameraPose linearInterpolatedPose(double distance, double displacement);
/**
* Compute the interpolated camera pose at a certain distance along the path
*/
@@ -59,6 +59,7 @@ public:
const Path* currentPath() const;
double speedScale() const;
double arrivalDistanceFactor() const;
float linearRotationSpeedFactor() const;
bool hasCurrentPath() const;
bool hasFinished() const;
@@ -103,6 +104,7 @@ private:
properties::FloatProperty _speedScale;
properties::BoolProperty _applyIdleBehaviorOnFinish;
properties::DoubleProperty _arrivalDistanceFactor;
properties::FloatProperty _linearRotationSpeedFactor;
properties::DoubleProperty _minValidBoundingSphere;
properties::StringListProperty _relevantNodeTags;
@@ -89,13 +89,13 @@ struct CameraKeyframe {
sizeof(_followNodeRotation)
);
int nodeNameLength = static_cast<int>(_focusNode.size());
uint32_t nodeNameLength = static_cast<uint32_t>(_focusNode.size());
// Add focus node
buffer.insert(
buffer.end(),
reinterpret_cast<const char*>(&nodeNameLength),
reinterpret_cast<const char*>(&nodeNameLength) + sizeof(nodeNameLength)
reinterpret_cast<const char*>(&nodeNameLength) + sizeof(uint32_t)
);
buffer.insert(
buffer.end(),
@@ -42,14 +42,13 @@ public:
Host
};
enum class MessageType : uint32_t {
enum class MessageType : uint8_t {
Authentication = 0,
Data,
ConnectionStatus,
HostshipRequest,
HostshipResignation,
NConnections,
Disconnection
NConnections
};
struct Message {
@@ -71,7 +70,9 @@ public:
class ConnectionLostError : public ghoul::RuntimeError {
public:
explicit ConnectionLostError();
explicit ConnectionLostError(bool shouldLogError = true);
bool shouldLogError;
};
ParallelConnection(std::unique_ptr<ghoul::io::TcpSocket> socket);
@@ -84,9 +85,11 @@ public:
ParallelConnection::Message receiveMessage();
static const unsigned int ProtocolVersion;
static const uint8_t ProtocolVersion;
private:
std::unique_ptr<ghoul::io::TcpSocket> _socket;
bool _shouldDisconnect = false;
};
} // namespace openspace
-117
View File
@@ -1,117 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___PARALLELSERVER___H__
#define __OPENSPACE_CORE___PARALLELSERVER___H__
#include <openspace/network/parallelconnection.h>
#include <openspace/util/concurrentqueue.h>
#include <ghoul/io/socket/tcpsocketserver.h>
#include <atomic>
#include <string>
#include <unordered_map>
namespace openspace {
class ParallelServer {
public:
void start(int port, const std::string& password,
const std::string& changeHostPassword);
void setDefaultHostAddress(std::string defaultHostAddress);
std::string defaultHostAddress() const;
void stop();
size_t nConnections() const;
private:
struct Peer {
size_t id;
std::string name;
ParallelConnection parallelConnection;
ParallelConnection::Status status;
std::thread thread;
};
struct PeerMessage {
size_t peerId;
ParallelConnection::Message message;
};
bool isConnected(const Peer& peer) const;
void sendMessage(Peer& peer, ParallelConnection::MessageType messageType,
const std::vector<char>& message);
void sendMessageToAll(ParallelConnection::MessageType messageType,
const std::vector<char>& message);
void sendMessageToClients(ParallelConnection::MessageType messageType,
const std::vector<char>& message);
void disconnect(Peer& peer);
void setName(Peer& peer, std::string name);
void assignHost(std::shared_ptr<Peer> newHost);
void setToClient(Peer& peer);
void setNConnections(size_t nConnections);
void sendConnectionStatus(Peer& peer);
void handleAuthentication(std::shared_ptr<Peer> peer, std::vector<char> message);
void handleData(const Peer& peer, std::vector<char> data);
void handleHostshipRequest(std::shared_ptr<Peer> peer, std::vector<char> message);
void handleHostshipResignation(Peer& peer);
void handleNewPeers();
void eventLoop();
std::shared_ptr<Peer> peer(size_t id);
void handlePeer(size_t id);
void handlePeerMessage(PeerMessage peerMessage);
std::unordered_map<size_t, std::shared_ptr<Peer>> _peers;
mutable std::mutex _peerListMutex;
std::thread _serverThread;
std::thread _eventLoopThread;
ghoul::io::TcpSocketServer _socketServer;
size_t _passwordHash;
size_t _changeHostPasswordHash;
size_t _nextConnectionId = 1;
std::atomic_bool _shouldStop = false;
std::atomic_size_t _nConnections = 0;
std::atomic_size_t _hostPeerId = 0;
mutable std::mutex _hostInfoMutex;
std::string _hostName;
std::string _defaultHostAddress;
ConcurrentQueue<PeerMessage> _incomingMessages;
};
} // namespace openspace
#endif // __OPENSPACE_CORE___PARALLELSERVER___H__
+4
View File
@@ -105,6 +105,7 @@ public:
protected:
properties::BoolProperty _enabled;
properties::FloatProperty _opacity;
properties::FloatProperty _fade;
properties::StringProperty _renderableType;
void setBoundingSphere(double boundingSphere);
@@ -113,6 +114,9 @@ protected:
void setRenderBinFromOpacity();
void registerUpdateRenderBinFromOpacity();
/// Returns the full opacity constructed from the _opactiy and _fade property values
float opacity() const;
double _boundingSphere = 0.0;
double _interactionSphere = 0.0;
SceneGraphNode* _parent = nullptr;
+1 -1
View File
@@ -172,7 +172,7 @@ private:
ghoul::opengl::OpenGLStateCache* _openglStateCache = nullptr;
properties::BoolProperty _showOverlayOnSlaves;
properties::BoolProperty _showOverlayOnClients;
properties::BoolProperty _showLog;
properties::FloatProperty _verticalLogOffset;
properties::BoolProperty _showVersionInfo;
@@ -88,6 +88,8 @@ protected:
virtual void bindTexture() = 0;
virtual void unbindTexture();
float opacity() const;
properties::BoolProperty _enabled;
properties::BoolProperty _usePerspectiveProjection;
properties::BoolProperty _useRadiusAzimuthElevation;
@@ -108,6 +110,7 @@ protected:
properties::Vec3Property _multiplyColor;
properties::Vec4Property _backgroundColor;
properties::FloatProperty _opacity;
properties::FloatProperty _fade;
properties::TriggerProperty _delete;
glm::ivec2 _objectSize = glm::ivec2(0);
+1 -2
View File
@@ -44,7 +44,7 @@ public:
static ghoul::mm_unique_ptr<Rotation> createFromDictionary(
const ghoul::Dictionary& dictionary);
Rotation(const ghoul::Dictionary& dictionary);
Rotation();
virtual ~Rotation() = default;
virtual bool initialize();
@@ -56,7 +56,6 @@ public:
static documentation::Documentation Documentation();
protected:
Rotation();
void requireUpdate();
private:
+4 -4
View File
@@ -115,10 +115,10 @@ private:
std::queue<QueueItem> _incomingScripts;
// Slave scripts are mutex protected since decode and rendering may
// happen asynchronously.
std::mutex _slaveScriptsMutex;
std::queue<std::string> _slaveScriptQueue;
// Client scripts are mutex protected since decode and rendering may happen
// asynchronously
std::mutex _clientScriptsMutex;
std::queue<std::string> _clientScriptQueue;
std::queue<QueueItem> _masterScriptQueue;
std::vector<std::string> _scriptsToSync;
+2 -2
View File
@@ -144,14 +144,14 @@ public:
/**
* Sets a relative time from profile.
*/
void setTimeRelativeFromProfile(const std::string& setTime);
static void setTimeRelativeFromProfile(const std::string& setTime);
/**
* Sets an absolute time from profile.
* \param setTime a string containing time to set, which must be a valid
* ISO 8601-like date string of the format YYYY-MM-DDTHH:MN:SS
*/
void setTimeAbsoluteFromProfile(const std::string& setTime);
static void setTimeAbsoluteFromProfile(const std::string& setTime);
/**
* Returns the Lua library that contains all Lua functions available to change the
@@ -154,7 +154,7 @@ void RenderableBoxGrid::render(const RenderData& data, RendererTasks&){
"MVPTransform",
glm::dmat4(data.camera.projectionMatrix()) * modelViewTransform
);
_gridProgram->setUniform("opacity", _opacity);
_gridProgram->setUniform("opacity", opacity());
_gridProgram->setUniform("gridColor", _color);
// Change GL state:
@@ -170,7 +170,7 @@ void RenderableGrid::render(const RenderData& data, RendererTasks&){
"MVPTransform",
glm::dmat4(data.camera.projectionMatrix()) * modelViewTransform
);
_gridProgram->setUniform("opacity", _opacity);
_gridProgram->setUniform("opacity", opacity());
_gridProgram->setUniform("gridColor", _color);
// Change GL state:
@@ -181,7 +181,7 @@ void RenderableRadialGrid::render(const RenderData& data, RendererTasks&) {
"MVPTransform",
glm::dmat4(data.camera.projectionMatrix()) * modelViewTransform
);
_gridProgram->setUniform("opacity", _opacity);
_gridProgram->setUniform("opacity", opacity());
_gridProgram->setUniform("gridColor", _color);
// Change GL state:
@@ -172,7 +172,7 @@ void RenderableSphericalGrid::render(const RenderData& data, RendererTasks&){
"MVPTransform",
glm::dmat4(data.camera.projectionMatrix()) * modelViewTransform
);
_gridProgram->setUniform("opacity", _opacity);
_gridProgram->setUniform("opacity", opacity());
_gridProgram->setUniform("gridColor", _color);
// Change GL state:
+1 -1
View File
@@ -155,7 +155,7 @@ void RenderableDisc::render(const RenderData& data, RendererTasks&) {
data.camera.projectionMatrix() * glm::mat4(modelViewTransform)
);
_shader->setUniform(_uniformCache.width, _width);
_shader->setUniform(_uniformCache.opacity, _opacity);
_shader->setUniform(_uniformCache.opacity, opacity());
ghoul::opengl::TextureUnit unit;
unit.activate();
+1 -1
View File
@@ -439,7 +439,7 @@ void RenderableLabels::renderLabels(const RenderData& data,
glm::vec4 textColor = glm::vec4(glm::vec3(_color), 1.f);
textColor.a *= fadeInVariable;
textColor.a *= _opacity;
textColor.a *= opacity();
ghoul::fontrendering::FontRenderer::ProjectedLabelsInformation labelInfo;
+1 -1
View File
@@ -579,7 +579,7 @@ void RenderableModel::render(const RenderData& data, RendererTasks&) {
if (distanceToCamera < maxDistance) {
_program->activate();
_program->setUniform(_uniformCache.opacity, _opacity);
_program->setUniform(_uniformCache.opacity, opacity());
// Model transform and view transform needs to be in double precision
const glm::dmat4 modelTransform =
@@ -270,7 +270,7 @@ void RenderableNodeLine::render(const RenderData& data, RendererTasks&) {
_program->setUniform("modelViewTransform", glm::mat4(modelViewTransform));
_program->setUniform("projectionTransform", data.camera.projectionMatrix());
_program->setUniform("color", glm::vec4(_lineColor.value(), _opacity));
_program->setUniform("color", glm::vec4(_lineColor.value(), opacity()));
// Change GL state:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+1 -1
View File
@@ -217,7 +217,7 @@ void RenderablePlane::render(const RenderData& data, RendererTasks&) {
ZoneScoped
_shader->activate();
_shader->setUniform("opacity", _opacity);
_shader->setUniform("opacity", opacity());
_shader->setUniform("mirrorBackside", _mirrorBackside);
+1 -1
View File
@@ -318,7 +318,7 @@ void RenderablePrism::render(const RenderData& data, RendererTasks&) {
// Uniforms
_shader->setUniform(_uniformCache.modelViewProjection, modelViewProjectionTransform);
_shader->setUniform(_uniformCache.color, glm::vec4(_lineColor.value(), _opacity));
_shader->setUniform(_uniformCache.color, glm::vec4(_lineColor.value(), opacity()));
// Render
glEnable(GL_PRIMITIVE_RESTART);
+1 -1
View File
@@ -280,7 +280,7 @@ void RenderableSphere::render(const RenderData& data, RendererTasks&) {
);
_shader->setUniform(_uniformCache.modelViewRotation, modelViewRotation);
float adjustedOpacity = _opacity;
float adjustedOpacity = opacity();
if (!_disableFadeInDistance) {
if (_fadeInThreshold > -1.0) {
@@ -275,7 +275,7 @@ void RenderableTimeVaryingSphere::render(const RenderData& data, RendererTasks&)
);
_shader->setUniform(_uniformCache.modelViewRotation, modelViewRotation);
float adjustedOpacity = _opacity;
float adjustedOpacity = opacity();
if (!_disableFadeInDistance) {
if (_fadeInThreshold > -1.0) {
+1 -1
View File
@@ -384,7 +384,7 @@ void RenderableTrail::render(const RenderData& data, RendererTasks&) {
ZoneScoped
_programObject->activate();
_programObject->setUniform(_uniformCache.opacity, _opacity);
_programObject->setUniform(_uniformCache.opacity, opacity());
glm::dmat4 modelTransform =
glm::translate(glm::dmat4(1.0), data.modelTransform.translation) *
@@ -683,7 +683,7 @@ void RenderableBillboardsCloud::renderBillboards(const RenderData& data,
_program->setUniform(_uniformCache.minBillboardSize, minBillboardSize);
_program->setUniform(_uniformCache.maxBillboardSize, maxBillboardSize);
_program->setUniform(_uniformCache.color, _pointColor);
_program->setUniform(_uniformCache.alphaValue, _opacity);
_program->setUniform(_uniformCache.alphaValue, opacity());
_program->setUniform(_uniformCache.scaleFactor, _scaleFactor);
_program->setUniform(_uniformCache.up, glm::vec3(orthoUp));
_program->setUniform(_uniformCache.right, glm::vec3(orthoRight));
@@ -320,7 +320,7 @@ void RenderableDUMeshes::renderMeshes(const RenderData&,
_program->setUniform(_uniformCache.modelViewTransform, modelViewMatrix);
_program->setUniform(_uniformCache.projectionTransform, projectionMatrix);
_program->setUniform(_uniformCache.alphaValue, _opacity);
_program->setUniform(_uniformCache.alphaValue, opacity());
for (const std::pair<const int, RenderingMesh>& pair : _renderingMeshesMap) {
_program->setUniform(_uniformCache.color, _meshColorMap[pair.second.colorIndex]);
@@ -455,7 +455,7 @@ void RenderablePlanesCloud::renderPlanes(const RenderData&,
_uniformCache.modelViewProjectionTransform,
modelViewProjectionMatrix
);
_program->setUniform(_uniformCache.alphaValue, _opacity);
_program->setUniform(_uniformCache.alphaValue, opacity());
_program->setUniform(_uniformCache.fadeInValue, fadeInVariable);
glDisable(GL_CULL_FACE);
@@ -242,7 +242,7 @@ void RenderablePoints::render(const RenderData& data, RendererTasks&) {
_program->setUniform(_uniformCache.color, _pointColor);
_program->setUniform(_uniformCache.sides, 4);
_program->setUniform(_uniformCache.alphaValue, _opacity);
_program->setUniform(_uniformCache.alphaValue, opacity());
_program->setUniform(_uniformCache.scaleFactor, _scaleFactor);
if (_hasSpriteTexture) {
@@ -176,7 +176,7 @@ void RenderableOrbitDisc::render(const RenderData& data, RendererTasks&) {
data.camera.projectionMatrix() * glm::mat4(modelViewTransform)
);
_shader->setUniform(_uniformCache.offset, _offset);
_shader->setUniform(_uniformCache.opacity, _opacity);
_shader->setUniform(_uniformCache.opacity, opacity());
_shader->setUniform(_uniformCache.eccentricity, _eccentricity);
_shader->setUniform(_uniformCache.semiMajorAxis, _size);
@@ -967,8 +967,8 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&,
_globalRenderer.program->setUniform("orenNayarRoughness", onr);
}
_localRenderer.program->setUniform("opacity", _opacity);
_globalRenderer.program->setUniform("opacity", _opacity);
_localRenderer.program->setUniform("opacity", opacity());
_globalRenderer.program->setUniform("opacity", opacity());
if (_globalRenderer.updatedSinceLastCall) {
@@ -150,7 +150,7 @@ void RenderableHabitableZone::render(const RenderData& data, RendererTasks&) {
data.camera.projectionMatrix() * glm::mat4(modelViewTransform)
);
_shader->setUniform(_uniformCache.width, _width);
_shader->setUniform(_uniformCache.opacity, _opacity);
_shader->setUniform(_uniformCache.opacity, opacity());
_shader->setUniform(_uniformCache.conservativeBounds, _conservativeBounds);
_shader->setUniform(_uniformCache.showOptimistic, _showOptimistic);
@@ -451,7 +451,7 @@ void RenderableOrbitalKepler::render(const RenderData& data, RendererTasks&) {
}
_programObject->activate();
_programObject->setUniform(_uniformCache.opacity, _opacity);
_programObject->setUniform(_uniformCache.opacity, opacity());
_programObject->setUniform(_uniformCache.inGameTime, data.time.j2000Seconds());
glm::dmat4 modelTransform =
+2 -2
View File
@@ -1034,10 +1034,10 @@ void RenderableStars::render(const RenderData& data, RendererTasks&) {
const double funcValue = a * distCamera + b;
fadeInVariable *= static_cast<float>(funcValue > 1.f ? 1.f : funcValue);
_program->setUniform(_uniformCache.alphaValue, _opacity * fadeInVariable);
_program->setUniform(_uniformCache.alphaValue, opacity() * fadeInVariable);
}
else {
_program->setUniform(_uniformCache.alphaValue, _opacity);
_program->setUniform(_uniformCache.alphaValue, opacity());
}
ghoul::opengl::TextureUnit psfUnit;
@@ -290,7 +290,7 @@ void RenderableTravelSpeed::update(const UpdateData& data) {
}
_shaderProgram->setUniform("lineColor", _lineColor);
_shaderProgram->setUniform("opacity", _opacity);
_shaderProgram->setUniform("opacity", opacity());
}
void RenderableTravelSpeed::render(const RenderData& data, RendererTasks& ) {
@@ -45,13 +45,19 @@ namespace {
constexpr const char* _loggerCat = "RenderablePlaneProjection";
constexpr const char* GalacticFrame = "GALACTIC";
// @TODO (emmbr 2022-01-20) Add documentation
struct [[codegen::Dictionary(RenderablePlaneProjection)]] Parameters {
std::optional<std::string> spacecraft;
std::optional<std::string> instrument;
std::optional<bool> moving;
std::optional<std::string> name;
// The SPICE name of the spacecraft from which the projection is performed
std::string spacecraft;
// The SPICE name of the instrument that is used to project the image onto this
// RenderablePlaneProjection
std::string instrument;
// The SPICE name of the default target that is imaged by this planet
std::optional<std::string> defaultTarget;
// The image that is used on this plane before any image is loaded from the
// ImageSequencerr
std::optional<std::string> texture;
};
#include "renderableplaneprojection_codegen.cpp"
@@ -60,17 +66,15 @@ namespace {
namespace openspace {
documentation::Documentation RenderablePlaneProjection::Documentation() {
return codegen::doc<Parameters>("spacecraftinstruments_renderableorbitdisc");
return codegen::doc<Parameters>("spacecraftinstruments_renderableplaneprojection");
}
RenderablePlaneProjection::RenderablePlaneProjection(const ghoul::Dictionary& dict)
: Renderable(dict)
{
const Parameters p = codegen::bake<Parameters>(dict);
_spacecraft = p.spacecraft.value_or(_spacecraft);
_instrument = p.instrument.value_or(_instrument);
_moving = p.moving.value_or(_moving);
_name = p.name.value_or(_name);
_spacecraft = p.spacecraft;
_instrument = p.instrument;
_defaultTarget = p.defaultTarget.value_or(_defaultTarget);
if (p.texture.has_value()) {
@@ -118,7 +122,7 @@ void RenderablePlaneProjection::render(const RenderData& data, RendererTasks&) {
_instrument
);
if (!_hasImage || (_moving && !active)) {
if (!_hasImage) {
return;
}
@@ -161,7 +165,7 @@ void RenderablePlaneProjection::update(const UpdateData& data) {
const double timePast = std::abs(img.timeRange.start - _previousTime);
if (_moving || _planeIsDirty) {
if (_planeIsDirty) {
updatePlane(img, time);
}
else if (timePast > std::numeric_limits<double>::epsilon()) {
@@ -245,9 +249,7 @@ void RenderablePlaneProjection::updatePlane(const Image& img, double currentTime
) * bounds[j];
glm::dvec3 cornerPosition = glm::proj(vecToTarget, bounds[j]);
if (!_moving) {
cornerPosition -= vecToTarget;
}
cornerPosition -= vecToTarget;
cornerPosition = SpiceManager::ref().frameTransformationMatrix(
GalacticFrame,
_target.frame,
@@ -258,15 +260,6 @@ void RenderablePlaneProjection::updatePlane(const Image& img, double currentTime
projection[j] = glm::vec3(cornerPosition * 1000.0);
}
if (!_moving) {
Scene* scene = global::renderEngine->scene();
SceneGraphNode* thisNode = scene->sceneGraphNode(_name);
SceneGraphNode* newParent = scene->sceneGraphNode(_target.node);
if (thisNode && newParent) {
thisNode->setParent(*newParent);
}
}
const GLfloat vertex_data[] = {
// square of two triangles drawn within fov in target coordinates
// x y z w s t
@@ -299,7 +292,7 @@ void RenderablePlaneProjection::updatePlane(const Image& img, double currentTime
reinterpret_cast<void*>(sizeof(GLfloat) * 4)
);
if (!_moving && !img.path.empty()) {
if (!img.path.empty()) {
_texturePath = img.path;
loadTexture();
}
@@ -86,8 +86,6 @@ private:
std::string frame;
std::string node;
} _target;
std::string _name = "ImagePlane";
bool _moving = false;
bool _hasImage = false;
};
@@ -265,7 +265,7 @@ void RenderableShadowCylinder::render(const RenderData& data, RendererTasks&) {
);
_shader->setUniform(_uniformCache.shadowColor, _shadowColor);
_shader->setUniform(_uniformCache.opacity, _opacity);
_shader->setUniform(_uniformCache.opacity, opacity());
glBindVertexArray(_vao);
glDrawArrays(GL_TRIANGLE_STRIP, 0, static_cast<GLsizei>(_vertices.size()));
@@ -140,7 +140,7 @@ RenderableToyVolume::RenderableToyVolume(const ghoul::Dictionary& dictionary)
RenderableToyVolume::~RenderableToyVolume() {}
void RenderableToyVolume::initializeGL() {
glm::vec4 color(glm::vec3(_color), _opacity);
glm::vec4 color(glm::vec3(_color), opacity());
_raycaster = std::make_unique<ToyVolumeRaycaster>(color);
_raycaster->initialize();
@@ -197,7 +197,7 @@ void RenderableToyVolume::update(const UpdateData& data) {
std::pow(10.f, static_cast<float>(_scalingExponent))
);
glm::vec4 color(glm::vec3(_color), _opacity);
glm::vec4 color(glm::vec3(_color), opacity());
_raycaster->setColor(color);
_raycaster->setStepSize(_stepSize);
@@ -137,7 +137,7 @@ void BasicVolumeRaycaster::preRaycast(const RaycastData& data,
program.setUniform("nClips_" + id, nClips);
program.setUniform("clipNormals_" + id, clipNormals);
program.setUniform("clipOffsets_" + id, clipOffsets);
program.setUniform("opacity_" + id, _opacity);
program.setUniform("opacity_" + id, opacity());
program.setUniform("rNormalization_" + id, _rNormalization);
program.setUniform("rUpperBound_" + id, _rUpperBound);
}
@@ -452,7 +452,7 @@ void RenderableTimeVaryingVolume::update(const UpdateData&) {
_raycaster->setVolumeTexture(nullptr);
}
_raycaster->setStepSize(_stepSize);
_raycaster->setOpacity(_opacity);
_raycaster->setOpacity(opacity());
_raycaster->setRNormalization(_rNormalization);
_raycaster->setRUpperBound(_rUpperBound);
}
-2
View File
@@ -82,7 +82,6 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/network/parallelconnection.cpp
${OPENSPACE_BASE_DIR}/src/network/parallelpeer.cpp
${OPENSPACE_BASE_DIR}/src/network/parallelpeer_lua.inl
${OPENSPACE_BASE_DIR}/src/network/parallelserver.cpp
${OPENSPACE_BASE_DIR}/src/properties/optionproperty.cpp
${OPENSPACE_BASE_DIR}/src/properties/property.cpp
${OPENSPACE_BASE_DIR}/src/properties/propertyowner.cpp
@@ -262,7 +261,6 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/navigation/waypoint.h
${OPENSPACE_BASE_DIR}/include/openspace/network/parallelconnection.h
${OPENSPACE_BASE_DIR}/include/openspace/network/parallelpeer.h
${OPENSPACE_BASE_DIR}/include/openspace/network/parallelserver.h
${OPENSPACE_BASE_DIR}/include/openspace/network/messagestructures.h
${OPENSPACE_BASE_DIR}/include/openspace/network/messagestructureshelper.h
${OPENSPACE_BASE_DIR}/include/openspace/properties/listproperty.h
+7 -1
View File
@@ -1659,8 +1659,14 @@ void OpenSpaceEngine::removeModeChangeCallback(CallbackHandle handle) {
void setCameraFromProfile(const Profile& p) {
if (!p.camera.has_value()) {
throw ghoul::RuntimeError("No 'camera' entry exists in the startup profile");
// If the camera is not specified, we want to set it to a sensible default value
interaction::NavigationState nav;
nav.anchor = "Root";
nav.referenceFrame = "Root";
global::navigationHandler->setNavigationStateNextFrame(nav);
return;
}
std::visit(
overloaded{
[](const Profile::CameraNavState& navStateProfile) {
+1 -1
View File
@@ -48,7 +48,7 @@ std::vector<std::byte> SyncEngine::encodeSyncables() {
return data;
}
// Should be called on sgct slaves
// Should be called on sgct clients
void SyncEngine::decodeSyncables(std::vector<std::byte> data) {
_syncBuffer.setData(std::move(data));
for (Syncable* syncable : _syncables) {
+106 -51
View File
@@ -40,6 +40,7 @@
#include <openspace/util/universalhelpers.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/interpolator.h>
#include <glm/ext/quaternion_relational.hpp>
namespace {
constexpr const char _loggerCat[] = "Path";
@@ -131,7 +132,6 @@ Path::Path(Waypoint start, Waypoint end, Type type,
// We now know how long it took to traverse the path. Use that
_speedFactorFromDuration = _progressedTime / *duration;
resetPlaybackVariables();
}
}
@@ -161,23 +161,7 @@ CameraPose Path::traversePath(double dt, float speedScale) {
if (_type == Type::Linear) {
// Special handling of linear paths, so that it can be used when we are
// traversing very large distances without introducing precision problems
const glm::dvec3 prevPosToEnd = _prevPose.position - _end.position();
const double remainingDistance = glm::length(prevPosToEnd);
// Actual displacement may not be bigger than remaining distance
if (displacement > remainingDistance) {
displacement = remainingDistance;
_traveledDistance = pathLength();
_shouldQuit = true;
return _end.pose();
}
// Just move along the line from the current position to the target
newPose.position = _prevPose.position -
displacement * glm::normalize(prevPosToEnd);
const double relativeDistance = _traveledDistance / pathLength();
newPose.rotation = interpolateRotation(relativeDistance);
newPose = linearInterpolatedPose(_traveledDistance, displacement);
}
else {
if (std::abs(prevDistance - _traveledDistance) < LengthEpsilon) {
@@ -204,7 +188,14 @@ bool Path::hasReachedEnd() const {
return true;
}
return (_traveledDistance / pathLength()) >= 1.0;
bool isPositionFinished = (_traveledDistance / pathLength()) >= 1.0;
bool isRotationFinished = glm::all(glm::equal(
_prevPose.rotation,
_end.rotation(),
glm::epsilon<double>()
));
return isPositionFinished && isRotationFinished;
}
void Path::resetPlaybackVariables() {
@@ -214,6 +205,28 @@ void Path::resetPlaybackVariables() {
_shouldQuit = false;
}
CameraPose Path::linearInterpolatedPose(double distance, double displacement) {
ghoul_assert(_type == Type::Linear, "Path type must be linear");
const double relativeDistance = distance / pathLength();
const glm::dvec3 prevPosToEnd = _prevPose.position - _end.position();
const double remainingDistance = glm::length(prevPosToEnd);
CameraPose pose;
// Actual displacement may not be bigger than remaining distance
if (displacement > remainingDistance) {
_traveledDistance = pathLength();
pose.position = _end.position();
}
else {
// Just move along line from the current position to the target
const glm::dvec3 lineDir = glm::normalize(prevPosToEnd);
pose.position = _prevPose.position - displacement * lineDir;
}
pose.rotation = linearPathRotation(relativeDistance);
return pose;
}
CameraPose Path::interpolatedPose(double distance) const {
const double relativeDistance = distance / pathLength();
CameraPose cs;
@@ -227,6 +240,8 @@ glm::dquat Path::interpolateRotation(double t) const {
case Type::AvoidCollision:
return easedSlerpRotation(t);
case Type::Linear:
// @TODO (2022-03-29, emmbr) Fix so that rendering the rotation of linear
// paths works again. I.e. openspace.debugging.renderCameraPath
return linearPathRotation(t);
case Type::ZoomOutOverview:
case Type::AvoidCollisionWithLookAt:
@@ -243,45 +258,59 @@ glm::dquat Path::easedSlerpRotation(double t) const {
}
glm::dquat Path::linearPathRotation(double t) const {
const double tHalf = 0.5;
const glm::dvec3 a = ghoul::viewDirection(_start.rotation());
const glm::dvec3 b = ghoul::viewDirection(_end.rotation());
const double angle = std::acos(glm::dot(a, b)); // assumes length 1.0 for a & b
const glm::dvec3 endNodePos = _end.node()->worldPosition();
const glm::dvec3 endUp = _end.rotation() * glm::dvec3(0.0, 1.0, 0.0);
// Seconds per pi angles. Per default, it takes 5 seconds to turn 90 degrees
double factor = 5.0 / glm::half_pi<double>();
factor *= global::navigationHandler->pathNavigator().linearRotationSpeedFactor();
if (t < tHalf) {
// Interpolate to look at target
const glm::dvec3 halfWayPosition = _curve->positionAt(tHalf);
const glm::dquat q = ghoul::lookAtQuaternion(halfWayPosition, endNodePos, endUp);
double turnDuration = std::max(angle * factor, 1.0); // Always at least 1 second
const double time = glm::clamp(_progressedTime / turnDuration, 0.0, 1.0);
return easedSlerpRotation(time);
const double tScaled = ghoul::sineEaseInOut(t / tHalf);
return glm::slerp(_start.rotation(), q, tScaled);
}
// @TODO (2022-03-18, emmbr) Leaving this for now, as something similar might have to
// be implemented for navigation states. But should be removed/reimplemented
// This distance is guaranteed to be strictly decreasing for linear paths
const double distanceToEnd = glm::distance(_prevPose.position, _end.position());
//const glm::dvec3 endNodePos = _end.node()->worldPosition();
//const glm::dvec3 endUp = _end.rotation() * glm::dvec3(0.0, 1.0, 0.0);
// Determine the distance at which to start interpolating to the target rotation.
// The magic numbers here are just randomly picked constants, set to make the
// resulting rotation look ok-ish
double closingUpDistance = 10.0 * _end.validBoundingSphere();
if (pathLength() < 2.0 * closingUpDistance) {
closingUpDistance = 0.2 * pathLength();
}
//const double tHalf = 0.5;
//if (t < tHalf) {
// // Interpolate to look at target
// const glm::dvec3 halfWayPosition = _curve->positionAt(tHalf);
// const glm::dquat q = ghoul::lookAtQuaternion(halfWayPosition, endNodePos, endUp);
if (distanceToEnd < closingUpDistance) {
// Interpolate to target rotation
const double tScaled = ghoul::sineEaseInOut(1.0 - distanceToEnd / closingUpDistance);
// const double tScaled = ghoul::sineEaseInOut(t / tHalf);
// return glm::slerp(_start.rotation(), q, tScaled);
//}
// Compute a position in front of the camera at the end orientation
const double inFrontDistance = glm::distance(_end.position(), endNodePos);
const glm::dvec3 viewDir = ghoul::viewDirection(_end.rotation());
const glm::dvec3 inFrontOfEnd = _end.position() + inFrontDistance * viewDir;
const glm::dvec3 lookAtPos = ghoul::interpolateLinear(tScaled, endNodePos, inFrontOfEnd);
return ghoul::lookAtQuaternion(_prevPose.position, lookAtPos, endUp);
}
//// This distance is guaranteed to be strictly decreasing for linear paths
//const double distanceToEnd = glm::distance(_prevPose.position, _end.position());
// Keep looking at the end node
return ghoul::lookAtQuaternion(_prevPose.position, endNodePos, endUp);
//// Determine the distance at which to start interpolating to the target rotation.
//// The magic numbers here are just randomly picked constants, set to make the
//// resulting rotation look ok-ish
//double closingUpDistance = 10.0 * _end.validBoundingSphere();
//if (pathLength() < 2.0 * closingUpDistance) {
// closingUpDistance = 0.2 * pathLength();
//}
//if (distanceToEnd < closingUpDistance) {
// // Interpolate to target rotation
// const double tScaled = ghoul::sineEaseInOut(1.0 - distanceToEnd / closingUpDistance);
// // Compute a position in front of the camera at the end orientation
// const double inFrontDistance = glm::distance(_end.position(), endNodePos);
// const glm::dvec3 viewDir = ghoul::viewDirection(_end.rotation());
// const glm::dvec3 inFrontOfEnd = _end.position() + inFrontDistance * viewDir;
// const glm::dvec3 lookAtPos = ghoul::interpolateLinear(tScaled, endNodePos, inFrontOfEnd);
// return ghoul::lookAtQuaternion(_prevPose.position, lookAtPos, endUp);
//}
//// Keep looking at the end node
//return ghoul::lookAtQuaternion(_prevPose.position, endNodePos, endUp);
}
glm::dquat Path::lookAtTargetsRotation(double t) const {
@@ -350,8 +379,17 @@ double Path::speedAlongPath(double traveledDistance) const {
double startUpDistance = DampenDistanceFactor * _start.validBoundingSphere();
double closeUpDistance = DampenDistanceFactor * _end.validBoundingSphere();
// Kind of an ugly workaround to make damping behave over very long paths, and/or
// where the target nodes might have large bounding spheres. The current max is set
// based on the order of magnitude of the solar system, which ofc is very specific to
// our space content...
// @TODO (2022-03-22, emmbr) Come up with a better more general solution
constexpr const double MaxDistance = 1E12;
startUpDistance = glm::min(MaxDistance, startUpDistance);
closeUpDistance = glm::min(MaxDistance, closeUpDistance);
if (pathLength() < startUpDistance + closeUpDistance) {
startUpDistance = 0.49 * pathLength(); // a little less than half
startUpDistance = 0.4 * pathLength(); // a little less than half
closeUpDistance = startUpDistance;
}
@@ -619,6 +657,23 @@ Path createPathFromDictionary(const ghoul::Dictionary& dictionary,
p.useTargetUpDirection.value_or(false)
};
double startToTargetCenterDistance = glm::distance(
startPoint.position(),
targetNode->worldPosition()
);
// Use a linear path if camera start is within the bounding sphere
const PathNavigator& navigator = global::navigationHandler->pathNavigator();
const double bs = navigator.findValidBoundingSphere(targetNode);
bool withinTargetBoundingSphere = startToTargetCenterDistance < bs;
if (withinTargetBoundingSphere) {
LINFO(
"Camera is within the bounding sphere of the target node. "
"Using linear path"
);
type = Path::Type::Linear;
}
waypoints = { computeWaypointFromNodeInfo(info, startPoint, type) };
break;
}
+15 -1
View File
@@ -69,7 +69,7 @@ namespace {
constexpr openspace::properties::Property::PropertyInfo SpeedScaleInfo = {
"SpeedScale",
"Speed Scale",
"Scale factor that the speed will be mulitplied with during path traversal. "
"Scale factor that the speed will be multiplied with during path traversal. "
"Can be used to speed up or slow down the camera motion, depending on if the "
"value is larger than or smaller than one."
};
@@ -90,6 +90,14 @@ namespace {
"object."
};
constexpr openspace::properties::Property::PropertyInfo RotationSpeedFactorInfo = {
"RotationSpeedFactor",
"Rotation Speed Factor (Linear Path)",
"Affects how fast the camera rotates to the target rotation during a linear "
"path. A value of 1 means that the camera will rotate 90 degrees in about 5 "
"seconds. A value of 2 means twice that fast, and so on."
};
constexpr const openspace::properties::Property::PropertyInfo MinBoundingSphereInfo =
{
"MinimalValidBoundingSphere",
@@ -119,6 +127,7 @@ PathNavigator::PathNavigator()
, _speedScale(SpeedScaleInfo, 1.f, 0.01f, 2.f)
, _applyIdleBehaviorOnFinish(IdleBehaviorOnFinishInfo, false)
, _arrivalDistanceFactor(ArrivalDistanceFactorInfo, 2.0, 0.1, 20.0)
, _linearRotationSpeedFactor(RotationSpeedFactorInfo, 1.f, 0.1f, 2.f)
, _minValidBoundingSphere(MinBoundingSphereInfo, 10.0, 1.0, 3e10)
, _relevantNodeTags(RelevantNodeTagsInfo)
{
@@ -134,6 +143,7 @@ PathNavigator::PathNavigator()
addProperty(_speedScale);
addProperty(_applyIdleBehaviorOnFinish);
addProperty(_arrivalDistanceFactor);
addProperty(_linearRotationSpeedFactor);
addProperty(_minValidBoundingSphere);
_relevantNodeTags = std::vector<std::string>{
@@ -166,6 +176,10 @@ double PathNavigator::arrivalDistanceFactor() const {
return _arrivalDistanceFactor;
}
float PathNavigator::linearRotationSpeedFactor() const {
return _linearRotationSpeedFactor;
}
bool PathNavigator::hasCurrentPath() const {
return _currentPath != nullptr;
}
+30 -18
View File
@@ -37,7 +37,8 @@ namespace {
namespace openspace {
const unsigned int ParallelConnection::ProtocolVersion = 5;
// Gonna do some UTF-like magic once we reach 255 to introduce a second byte or something
const uint8_t ParallelConnection::ProtocolVersion = 6;
ParallelConnection::Message::Message(MessageType t, std::vector<char> c)
: type(t)
@@ -52,8 +53,9 @@ ParallelConnection::DataMessage::DataMessage(datamessagestructures::Type t,
, content(std::move(c))
{}
ParallelConnection::ConnectionLostError::ConnectionLostError()
ParallelConnection::ConnectionLostError::ConnectionLostError(bool shouldLogError_)
: ghoul::RuntimeError("Parallel connection lost", "ParallelConnection")
, shouldLogError(shouldLogError_)
{}
ParallelConnection::ParallelConnection(std::unique_ptr<ghoul::io::TcpSocket> socket)
@@ -65,14 +67,14 @@ bool ParallelConnection::isConnectedOrConnecting() const {
}
void ParallelConnection::sendDataMessage(const DataMessage& dataMessage) {
const uint32_t dataMessageTypeOut = static_cast<uint32_t>(dataMessage.type);
const uint8_t dataMessageTypeOut = static_cast<uint8_t>(dataMessage.type);
const double dataMessageTimestamp = dataMessage.timestamp;
std::vector<char> messageContent;
messageContent.insert(
messageContent.end(),
reinterpret_cast<const char*>(&dataMessageTypeOut),
reinterpret_cast<const char*>(&dataMessageTypeOut) + sizeof(uint32_t)
reinterpret_cast<const char*>(&dataMessageTypeOut) + sizeof(uint8_t)
);
messageContent.insert(
@@ -90,7 +92,7 @@ void ParallelConnection::sendDataMessage(const DataMessage& dataMessage) {
}
bool ParallelConnection::sendMessage(const Message& message) {
const uint32_t messageTypeOut = static_cast<uint32_t>(message.type);
const uint8_t messageTypeOut = static_cast<uint8_t>(message.type);
const uint32_t messageSizeOut = static_cast<uint32_t>(message.content.size());
std::vector<char> header;
@@ -100,12 +102,12 @@ bool ParallelConnection::sendMessage(const Message& message) {
header.insert(header.end(),
reinterpret_cast<const char*>(&ProtocolVersion),
reinterpret_cast<const char*>(&ProtocolVersion) + sizeof(uint32_t)
reinterpret_cast<const char*>(&ProtocolVersion) + sizeof(uint8_t)
);
header.insert(header.end(),
reinterpret_cast<const char*>(&messageTypeOut),
reinterpret_cast<const char*>(&messageTypeOut) + sizeof(uint32_t)
reinterpret_cast<const char*>(&messageTypeOut) + sizeof(uint8_t)
);
header.insert(header.end(),
@@ -123,6 +125,7 @@ bool ParallelConnection::sendMessage(const Message& message) {
}
void ParallelConnection::disconnect() {
_shouldDisconnect = true;
if (_socket) {
_socket->disconnect();
}
@@ -136,7 +139,9 @@ ParallelConnection::Message ParallelConnection::receiveMessage() {
// Header consists of...
constexpr size_t HeaderSize =
2 * sizeof(char) + // OS
3 * sizeof(uint32_t); // Protocol version, message type and message size
sizeof(uint8_t) + // Protocol version
sizeof(uint8_t) + // Message type
sizeof(uint32_t); // message size
// Create basic buffer for receiving first part of messages
std::vector<char> headerBuffer(HeaderSize);
@@ -144,20 +149,27 @@ ParallelConnection::Message ParallelConnection::receiveMessage() {
// Receive the header data
if (!_socket->get(headerBuffer.data(), HeaderSize)) {
LERROR("Failed to read header from socket. Disconencting.");
throw ConnectionLostError();
// The `get` call is blocking until something happens, so we might end up here if
// the socket properly closed or if the loading legitimately failed
if (_shouldDisconnect) {
throw ConnectionLostError(false);
}
else {
LERROR("Failed to read header from socket. Disconnecting");
throw ConnectionLostError();
}
}
// Make sure that header matches this version of OpenSpace
if (!(headerBuffer[0] == 'O' && headerBuffer[1] == 'S')) {
LERROR("Expected to read message header 'OS' from socket.");
LERROR("Expected to read message header 'OS' from socket");
throw ConnectionLostError();
}
size_t offset = 2;
const uint32_t protocolVersionIn =
*reinterpret_cast<uint32_t*>(headerBuffer.data() + offset);
offset += sizeof(uint32_t);
const uint8_t protocolVersionIn =
*reinterpret_cast<uint8_t*>(headerBuffer.data() + offset);
offset += sizeof(uint8_t);
if (protocolVersionIn != ProtocolVersion) {
LERROR(fmt::format(
@@ -168,9 +180,9 @@ ParallelConnection::Message ParallelConnection::receiveMessage() {
throw ConnectionLostError();
}
const uint32_t messageTypeIn =
*reinterpret_cast<uint32_t*>(headerBuffer.data() + offset);
offset += sizeof(uint32_t);
const uint8_t messageTypeIn =
*reinterpret_cast<uint8_t*>(headerBuffer.data() + offset);
offset += sizeof(uint8_t);
const uint32_t messageSizeIn =
*reinterpret_cast<uint32_t*>(headerBuffer.data() + offset);
@@ -181,7 +193,7 @@ ParallelConnection::Message ParallelConnection::receiveMessage() {
// Receive the payload
messageBuffer.resize(messageSize);
if (!_socket->get(messageBuffer.data(), messageSize)) {
LERROR("Failed to read message from socket. Disconencting.");
LERROR("Failed to read message from socket. Disconnecting");
throw ConnectionLostError();
}
+57 -26
View File
@@ -163,31 +163,59 @@ void ParallelPeer::disconnect() {
}
void ParallelPeer::sendAuthentication() {
std::string name = _name;
// Length of this nodes name
const uint32_t nameLength = static_cast<uint32_t>(name.length());
std::string password = _password;
if (password.size() > std::numeric_limits<uint16_t>::max()) {
password.resize(std::numeric_limits<uint16_t>::max());
}
const uint16_t passwordSize = static_cast<uint16_t>(password.size());
// Total size of the buffer: (passcode + namelength + name)
const size_t size = sizeof(uint64_t) + sizeof(uint32_t) + nameLength;
std::string hostPassword = _hostPassword;
if (hostPassword.size() > std::numeric_limits<uint16_t>::max()) {
hostPassword.resize(std::numeric_limits<uint16_t>::max());
}
const uint16_t hostPasswordSize = static_cast<uint16_t>(hostPassword.size());
std::string name = _name;
if (name.size() > std::numeric_limits<uint8_t>::max()) {
name.resize(std::numeric_limits<uint8_t>::max());
}
const uint8_t nameLength = static_cast<uint8_t>(name.length());
// Total size of the buffer
const size_t size =
sizeof(uint16_t) + // password length
passwordSize + // password
sizeof(uint16_t) + // host password length
hostPasswordSize + // host password
sizeof(uint8_t) + // name length
nameLength; // name
// Create and reserve buffer
std::vector<char> buffer;
buffer.reserve(size);
const uint64_t passCode = std::hash<std::string>{}(_password.value());
// Write the hashed password to buffer
// Write the password to buffer
buffer.insert(
buffer.end(),
reinterpret_cast<const char*>(&passCode),
reinterpret_cast<const char*>(&passCode) + sizeof(uint64_t)
reinterpret_cast<const char*>(&passwordSize),
reinterpret_cast<const char*>(&passwordSize) + sizeof(uint16_t)
);
buffer.insert(buffer.end(), password.begin(), password.end());
// Write the host password to buffer
buffer.insert(
buffer.end(),
reinterpret_cast<const char*>(&hostPasswordSize),
reinterpret_cast<const char*>(&hostPasswordSize) + sizeof(uint16_t)
);
buffer.insert(buffer.end(), hostPassword.begin(), hostPassword.end());
// Write the length of the nodes name to buffer
buffer.insert(
buffer.end(),
reinterpret_cast<const char*>(&nameLength),
reinterpret_cast<const char*>(&nameLength) + sizeof(uint32_t)
reinterpret_cast<const char*>(&nameLength) + sizeof(uint8_t)
);
// Write this node's name to buffer
@@ -265,8 +293,8 @@ void ParallelPeer::dataMessageReceived(const std::vector<char>& message) {
size_t offset = 0;
// The type of data message received
const uint32_t type = *(reinterpret_cast<const uint32_t*>(message.data() + offset));
offset += sizeof(uint32_t);
const uint8_t type = *(reinterpret_cast<const uint8_t*>(message.data() + offset));
offset += sizeof(uint8_t);
const double timestamp = *(reinterpret_cast<const double*>(message.data() + offset));
offset += sizeof(double);
@@ -363,19 +391,19 @@ void ParallelPeer::dataMessageReceived(const std::vector<char>& message) {
}
void ParallelPeer::connectionStatusMessageReceived(const std::vector<char>& message) {
if (message.size() < 2 * sizeof(uint32_t)) {
if (message.size() < 2 * sizeof(uint8_t)) {
LERROR("Malformed connection status message");
return;
}
size_t pointer = 0;
uint32_t statusIn = *(reinterpret_cast<const uint32_t*>(&message[pointer]));
const uint8_t statusIn = *(reinterpret_cast<const uint8_t*>(&message[pointer]));
const ParallelConnection::Status status = static_cast<ParallelConnection::Status>(
statusIn
);
pointer += sizeof(uint32_t);
pointer += sizeof(uint8_t);
const size_t hostNameSize = *(reinterpret_cast<const uint32_t*>(&message[pointer]));
pointer += sizeof(uint32_t);
const uint8_t hostNameSize = *(reinterpret_cast<const uint8_t*>(&message[pointer]));
pointer += sizeof(uint8_t);
if (hostNameSize > message.size() - pointer) {
LERROR("Malformed connection status message");
@@ -409,8 +437,7 @@ void ParallelPeer::connectionStatusMessageReceived(const std::vector<char>& mess
global::timeManager->clearKeyframes();
}
void ParallelPeer::nConnectionsMessageReceived(const std::vector<char>& message)
{
void ParallelPeer::nConnectionsMessageReceived(const std::vector<char>& message) {
if (message.size() < sizeof(uint32_t)) {
LERROR("Malformed host info message");
return;
@@ -424,8 +451,10 @@ void ParallelPeer::handleCommunication() {
try {
ParallelConnection::Message m = _connection.receiveMessage();
queueInMessage(m);
} catch (const ParallelConnection::ConnectionLostError&) {
LERROR("Parallel connection lost");
} catch (const ParallelConnection::ConnectionLostError& e) {
if (e.shouldLogError) {
LERROR("Parallel connection lost");
}
}
}
setStatus(ParallelConnection::Status::Disconnected);
@@ -445,12 +474,14 @@ void ParallelPeer::setName(std::string name) {
void ParallelPeer::requestHostship() {
std::vector<char> buffer;
uint64_t passwordHash = std::hash<std::string>{}(_hostPassword);
std::string hostPw = _hostPassword;
uint16_t hostPwSize = static_cast<uint16_t>(hostPw.size());
buffer.insert(
buffer.end(),
reinterpret_cast<char*>(&passwordHash),
reinterpret_cast<char*>(&passwordHash) + sizeof(uint64_t)
reinterpret_cast<const char*>(&hostPwSize),
reinterpret_cast<const char*>(&hostPwSize) + sizeof(uint16_t)
);
buffer.insert(buffer.end(), hostPw.begin(), hostPw.end());
_connection.sendMessage(ParallelConnection::Message(
ParallelConnection::MessageType::HostshipRequest,
@@ -504,7 +535,7 @@ void ParallelPeer::resetTimeOffset() {
void ParallelPeer::preSynchronization() {
ZoneScoped
std::unique_lock<std::mutex> unqlock(_receiveBufferMutex);
std::unique_lock<std::mutex> unlock(_receiveBufferMutex);
while (!_receiveBuffer.empty()) {
ParallelConnection::Message& message = _receiveBuffer.front();
handleMessage(message);
-426
View File
@@ -1,426 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/network/parallelserver.h>
#include <ghoul/fmt.h>
#include <ghoul/io/socket/tcpsocket.h>
#include <ghoul/logging/logmanager.h>
#include <functional>
// @TODO(abock): In the entire class remove std::shared_ptr<Peer> by const Peer& where
// possible to simplify the interface
namespace {
constexpr const char* _loggerCat = "ParallelServer";
} // namespace
namespace openspace {
void ParallelServer::start(int port, const std::string& password,
const std::string& changeHostPassword)
{
_socketServer.listen(port);
_passwordHash = std::hash<std::string>{}(password);
_changeHostPasswordHash = std::hash<std::string>{}(changeHostPassword);
_serverThread = std::thread([this](){ handleNewPeers(); });
_eventLoopThread = std::thread([this]() { eventLoop(); });
}
void ParallelServer::setDefaultHostAddress(std::string defaultHostAddress) {
std::lock_guard lock(_hostInfoMutex);
_defaultHostAddress = std::move(defaultHostAddress);
}
std::string ParallelServer::defaultHostAddress() const {
std::lock_guard lock(_hostInfoMutex);
return _defaultHostAddress;
}
void ParallelServer::stop() {
_shouldStop = true;
_socketServer.close();
}
void ParallelServer::handleNewPeers() {
while (!_shouldStop) {
std::unique_ptr<ghoul::io::TcpSocket> s = _socketServer.awaitPendingTcpSocket();
s->startStreams();
const size_t id = _nextConnectionId++;
auto p = std::make_shared<Peer>(Peer{
id,
"",
ParallelConnection(std::move(s)),
ParallelConnection::Status::Connecting,
std::thread()
});
auto it = _peers.emplace(p->id, p);
it.first->second->thread = std::thread([this, id]() { handlePeer(id); });
}
}
std::shared_ptr<ParallelServer::Peer> ParallelServer::peer(size_t id) {
std::lock_guard lock(_peerListMutex);
const auto it = _peers.find(id);
if (it == _peers.end()) {
return nullptr;
}
return it->second;
}
void ParallelServer::handlePeer(size_t id) {
while (!_shouldStop) {
std::shared_ptr<Peer> p = peer(id);
if (!p) {
return;
}
if (!p->parallelConnection.isConnectedOrConnecting()) {
return;
}
try {
ParallelConnection::Message m = p->parallelConnection.receiveMessage();
PeerMessage msg;
msg.peerId = id;
msg.message = m;
_incomingMessages.push(msg);
}
catch (const ParallelConnection::ConnectionLostError&) {
LERROR(fmt::format("Connection lost to {}", p->id));
PeerMessage msg;
msg.peerId = id;
msg.message = ParallelConnection::Message(
ParallelConnection::MessageType::Disconnection, std::vector<char>()
);
_incomingMessages.push(msg);
return;
}
}
}
void ParallelServer::eventLoop() {
while (!_shouldStop) {
PeerMessage pm = _incomingMessages.pop();
handlePeerMessage(std::move(pm));
}
}
void ParallelServer::handlePeerMessage(PeerMessage peerMessage) {
const size_t peerId = peerMessage.peerId;
auto it = _peers.find(peerId);
if (it == _peers.end()) {
return;
}
std::shared_ptr<Peer>& peer = it->second;
const ParallelConnection::MessageType type = peerMessage.message.type;
std::vector<char>& data = peerMessage.message.content;
switch (type) {
case ParallelConnection::MessageType::Authentication:
handleAuthentication(peer, std::move(data));
break;
case ParallelConnection::MessageType::Data:
handleData(*peer, std::move(data));
break;
case ParallelConnection::MessageType::HostshipRequest:
handleHostshipRequest(peer, std::move(data));
break;
case ParallelConnection::MessageType::HostshipResignation:
handleHostshipResignation(*peer);
break;
case ParallelConnection::MessageType::Disconnection:
disconnect(*peer);
break;
default:
LERROR(fmt::format("Unsupported message type: {}", static_cast<int>(type)));
break;
}
}
void ParallelServer::handleAuthentication(std::shared_ptr<Peer> peer,
std::vector<char> message)
{
std::stringstream input(std::string(message.begin(), message.end()));
// 8 bytes passcode
uint64_t passwordHash = 0;
input.read(reinterpret_cast<char*>(&passwordHash), sizeof(uint64_t));
if (passwordHash != _passwordHash) {
LERROR(fmt::format("Connection {} provided incorrect passcode.", peer->id));
disconnect(*peer);
return;
}
// 4 bytes name size
uint32_t nameSize = 0;
input.read(reinterpret_cast<char*>(&nameSize), sizeof(uint32_t));
// <nameSize> bytes name
std::string name(nameSize, static_cast<char>(0));
input.read(&name[0], nameSize);
if (nameSize == 0) {
name = "Anonymous";
}
setName(*peer, name);
LINFO(fmt::format("Connection established with {} ('{}')", peer->id, name));
std::string defaultHostAddress;
{
std::lock_guard _hostMutex(_hostInfoMutex);
defaultHostAddress = _defaultHostAddress;
}
if (_hostPeerId == 0 &&
peer->parallelConnection.socket()->address() == defaultHostAddress)
{
// Directly promote the conenction to host (initialize) if there is no host, and
// ip matches default host ip.
LINFO(fmt::format("Connection {} directly promoted to host", peer->id));
assignHost(peer);
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
// sendConnectionStatus(it->second) ?
sendConnectionStatus(*peer);
}
}
else {
setToClient(*peer);
}
setNConnections(nConnections() + 1);
}
void ParallelServer::handleData(const Peer& peer, std::vector<char> data) {
if (peer.id != _hostPeerId) {
LINFO(fmt::format(
"Ignoring connection {} trying to send data without being host", peer.id
));
}
sendMessageToClients(ParallelConnection::MessageType::Data, data);
}
void ParallelServer::handleHostshipRequest(std::shared_ptr<Peer> peer,
std::vector<char> message)
{
std::stringstream input(std::string(message.begin(), message.end()));
LINFO(fmt::format("Connection {} requested hostship", peer->id));
uint64_t passwordHash = 0;
input.read(reinterpret_cast<char*>(&passwordHash), sizeof(uint64_t));
if (passwordHash != _changeHostPasswordHash) {
LERROR(fmt::format("Connection {} provided incorrect host password", peer->id));
return;
}
size_t oldHostPeerId = 0;
{
std::lock_guard lock(_hostInfoMutex);
oldHostPeerId = _hostPeerId;
}
if (oldHostPeerId == peer->id) {
LINFO(fmt::format("Connection {} is already the host", peer->id));
return;
}
assignHost(peer);
LINFO(fmt::format("Switched host from {} to {}", oldHostPeerId, peer->id));
}
void ParallelServer::handleHostshipResignation(Peer& peer) {
LINFO(fmt::format("Connection {} wants to resign its hostship", peer.id));
setToClient(peer);
LINFO(fmt::format("Connection {} resigned as host", peer.id));
}
bool ParallelServer::isConnected(const Peer& peer) const {
return peer.status != ParallelConnection::Status::Connecting &&
peer.status != ParallelConnection::Status::Disconnected;
}
void ParallelServer::sendMessage(Peer& peer, ParallelConnection::MessageType messageType,
const std::vector<char>& message)
{
peer.parallelConnection.sendMessage({ messageType, message });
}
void ParallelServer::sendMessageToAll(ParallelConnection::MessageType messageType,
const std::vector<char>& message)
{
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
if (isConnected(*it.second)) {
it.second->parallelConnection.sendMessage({ messageType, message });
}
}
}
void ParallelServer::sendMessageToClients(ParallelConnection::MessageType messageType,
const std::vector<char>& message)
{
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
if (it.second->status == ParallelConnection::Status::ClientWithHost) {
it.second->parallelConnection.sendMessage({ messageType, message });
}
}
}
void ParallelServer::disconnect(Peer& peer) {
if (isConnected(peer)) {
setNConnections(nConnections() - 1);
}
size_t hostPeerId = 0;
{
std::lock_guard lock(_hostInfoMutex);
hostPeerId = _hostPeerId;
}
// Make sure any disconnecting host is first degraded to client, in order to notify
// other clients about host disconnection.
if (peer.id == hostPeerId) {
setToClient(peer);
}
peer.parallelConnection.disconnect();
peer.thread.join();
_peers.erase(peer.id);
}
void ParallelServer::setName(Peer& peer, std::string name) {
peer.name = std::move(name);
size_t hostPeerId = 0;
{
std::lock_guard lock(_hostInfoMutex);
hostPeerId = _hostPeerId;
}
// Make sure everyone gets the new host name.
if (peer.id == hostPeerId) {
{
std::lock_guard lock(_hostInfoMutex);
_hostName = peer.name;
}
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
// sendConnectionStatus(it->second) ?
sendConnectionStatus(peer);
}
}
}
void ParallelServer::assignHost(std::shared_ptr<Peer> newHost) {
{
std::lock_guard lock(_hostInfoMutex);
std::shared_ptr<ParallelServer::Peer> oldHost = peer(_hostPeerId);
if (oldHost) {
oldHost->status = ParallelConnection::Status::ClientWithHost;
}
_hostPeerId = newHost->id;
_hostName = newHost->name;
}
newHost->status = ParallelConnection::Status::Host;
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
if (it.second != newHost) {
it.second->status = ParallelConnection::Status::ClientWithHost;
}
sendConnectionStatus(*it.second);
}
}
void ParallelServer::setToClient(Peer& peer) {
if (peer.status == ParallelConnection::Status::Host) {
{
std::lock_guard lock(_hostInfoMutex);
_hostPeerId = 0;
_hostName.clear();
}
// If host becomes client, make all clients hostless.
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
it.second->status = ParallelConnection::Status::ClientWithoutHost;
sendConnectionStatus(*it.second);
}
}
else {
peer.status = (_hostPeerId > 0) ?
ParallelConnection::Status::ClientWithHost :
ParallelConnection::Status::ClientWithoutHost;
sendConnectionStatus(peer);
}
}
void ParallelServer::setNConnections(size_t nConnections) {
_nConnections = nConnections;
std::vector<char> data;
const uint32_t n = static_cast<uint32_t>(_nConnections);
data.insert(
data.end(),
reinterpret_cast<const char*>(&n),
reinterpret_cast<const char*>(&n) + sizeof(uint32_t)
);
sendMessageToAll(ParallelConnection::MessageType::NConnections, data);
}
void ParallelServer::sendConnectionStatus(Peer& peer) {
std::vector<char> data;
const uint32_t outStatus = static_cast<uint32_t>(peer.status);
data.insert(
data.end(),
reinterpret_cast<const char*>(&outStatus),
reinterpret_cast<const char*>(&outStatus) + sizeof(uint32_t)
);
const uint32_t outHostNameSize = static_cast<uint32_t>(_hostName.size());
data.insert(
data.end(),
reinterpret_cast<const char*>(&outHostNameSize),
reinterpret_cast<const char*>(&outHostNameSize) + sizeof(uint32_t)
);
data.insert(
data.end(),
_hostName.data(),
_hostName.data() + outHostNameSize
);
sendMessage(peer, ParallelConnection::MessageType::ConnectionStatus, data);
}
size_t ParallelServer::nConnections() const {
return _nConnections;
}
} // namespace openspace
+24 -3
View File
@@ -51,6 +51,18 @@ namespace {
"completely transparent."
};
constexpr openspace::properties::Property::PropertyInfo FadeInfo = {
"Fade",
"Fade",
"This value is used by the system to be able to fade out renderables "
"independently from the Opacity value selected by the user. This value should "
"not be directly manipulated through a user interface, but instead used by other "
"components of the system programmatically",
// The Developer mode should be used once the properties in the UI listen to this
// openspace::properties::Property::Visibility::Developer
openspace::properties::Property::Visibility::Hidden
};
constexpr openspace::properties::Property::PropertyInfo RenderableTypeInfo = {
"Type",
"Renderable Type",
@@ -58,7 +70,8 @@ namespace {
openspace::properties::Property::Visibility::Hidden
};
constexpr openspace::properties::Property::PropertyInfo RenderableRenderBinModeInfo = {
constexpr openspace::properties::Property::PropertyInfo RenderableRenderBinModeInfo =
{
"RenderBinMode",
"Render Bin Mode",
"This value specifies if the renderable should be rendered in the Background,"
@@ -128,6 +141,7 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary)
: properties::PropertyOwner({ "Renderable" })
, _enabled(EnabledInfo, true)
, _opacity(OpacityInfo, 1.f, 0.f, 1.f)
, _fade(FadeInfo, 1.f, 0.f, 1.f)
, _renderableType(RenderableTypeInfo, "Renderable")
{
ZoneScoped
@@ -158,6 +172,8 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary)
// We don't add the property here as subclasses should decide on their own whether
// they to expose the opacity or not
addProperty(_fade);
// set type for UI
_renderableType = p.type.value_or(_renderableType);
addProperty(_renderableType);
@@ -224,7 +240,7 @@ bool Renderable::matchesRenderBinMask(int binMask) {
}
bool Renderable::isVisible() const {
return _enabled;
return _enabled && _opacity > 0.f && _fade > 0.f;
}
bool Renderable::isReady() const {
@@ -249,7 +265,8 @@ void Renderable::setRenderBinFromOpacity() {
if ((_renderBin != Renderable::RenderBin::PostDeferredTransparent) &&
(_renderBin != Renderable::RenderBin::Overlay))
{
if (_opacity >= 0.f && _opacity < 1.f) {
const float v = opacity();
if (v >= 0.f && v < 1.f) {
setRenderBin(Renderable::RenderBin::PreDeferredTransparent);
}
else {
@@ -262,4 +279,8 @@ void Renderable::registerUpdateRenderBinFromOpacity() {
_opacity.onChange([this]() { setRenderBinFromOpacity(); });
}
float Renderable::opacity() const {
return _opacity * _fade;
}
} // namespace openspace
+9 -8
View File
@@ -94,11 +94,11 @@ namespace {
constexpr const char* KeyFontMono = "Mono";
constexpr const char* KeyFontLight = "Light";
constexpr openspace::properties::Property::PropertyInfo ShowOverlaySlavesInfo = {
"ShowOverlayOnSlaves",
"Show Overlay Information on Slaves",
constexpr openspace::properties::Property::PropertyInfo ShowOverlayClientsInfo = {
"ShowOverlayOnClients",
"Show Overlay Information on Clients",
"If this value is enabled, the overlay information text is also automatically "
"rendered on the slave nodes. This values is disabled by default."
"rendered on client nodes. This values is disabled by default."
};
constexpr openspace::properties::Property::PropertyInfo ShowLogInfo = {
@@ -280,7 +280,7 @@ namespace openspace {
RenderEngine::RenderEngine()
: properties::PropertyOwner({ "RenderEngine" })
, _showOverlayOnSlaves(ShowOverlaySlavesInfo, false)
, _showOverlayOnClients(ShowOverlayClientsInfo, false)
, _showLog(ShowLogInfo, true)
, _verticalLogOffset(VerticalLogOffsetInfo, 0.f, 0.f, 1.f)
, _showVersionInfo(ShowVersionInfo, true)
@@ -321,7 +321,7 @@ RenderEngine::RenderEngine()
, _enabledFontColor(EnabledFontColorInfo, glm::vec4(0.2f, 0.75f, 0.2f, 1.f))
, _disabledFontColor(DisabledFontColorInfo, glm::vec4(0.55f, 0.2f, 0.2f, 1.f))
{
addProperty(_showOverlayOnSlaves);
addProperty(_showOverlayOnClients);
addProperty(_showLog);
addProperty(_verticalLogOffset);
addProperty(_showVersionInfo);
@@ -804,7 +804,7 @@ void RenderEngine::renderOverlays(const ShutdownInformation& shutdownInfo) {
ZoneScoped
const bool isMaster = global::windowDelegate->isMaster();
if (isMaster || _showOverlayOnSlaves) {
if (isMaster || _showOverlayOnClients) {
renderScreenLog();
renderVersionInformation();
renderDashboard();
@@ -1072,7 +1072,8 @@ scripting::LuaLibrary RenderEngine::luaLibrary() {
{
codegen::lua::AddScreenSpaceRenderable,
codegen::lua::RemoveScreenSpaceRenderable,
codegen::lua::TakeScreenshot
codegen::lua::TakeScreenshot,
codegen::lua::DpiScaling
}
};
}
+6
View File
@@ -67,6 +67,12 @@ namespace {
return static_cast<int>(screenshotNumber);
}
// Extracts the DPI scaling for either the GUI window or if there is no dedicated GUI
// window, the first window.
[[codegen::luawrap]] float dpiScaling() {
return openspace::global::windowDelegate->osDpiScaling();
}
#include "renderengine_lua_codegen.cpp"
} // namespace
+17 -1
View File
@@ -124,6 +124,16 @@ namespace {
"completely transparent."
};
constexpr openspace::properties::Property::PropertyInfo FadeInfo = {
"Fade",
"Fade",
"This value is used by the system to be able to fade out renderables "
"independently from the Opacity value selected by the user. This value should "
"not be directly manipulated through a user interface, but instead used by other "
"components of the system programmatically",
openspace::properties::Property::Visibility::Developer
};
constexpr openspace::properties::Property::PropertyInfo DeleteInfo = {
"Delete",
"Delete",
@@ -350,6 +360,7 @@ ScreenSpaceRenderable::ScreenSpaceRenderable(const ghoul::Dictionary& dictionary
glm::vec4(1.f)
)
, _opacity(OpacityInfo, 1.f, 0.f, 1.f)
, _fade(FadeInfo, 1.f, 0.f, 1.f)
, _delete(DeleteInfo)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
@@ -383,6 +394,7 @@ ScreenSpaceRenderable::ScreenSpaceRenderable(const ghoul::Dictionary& dictionary
addProperty(_multiplyColor);
addProperty(_backgroundColor);
addProperty(_opacity);
addProperty(_fade);
addProperty(_localRotation);
@@ -589,7 +601,7 @@ void ScreenSpaceRenderable::draw(glm::mat4 modelTransform) {
_shader->activate();
_shader->setUniform(_uniformCache.color, _multiplyColor);
_shader->setUniform(_uniformCache.opacity, _opacity);
_shader->setUniform(_uniformCache.opacity, opacity());
_shader->setUniform(_uniformCache.backgroundColor, _backgroundColor);
_shader->setUniform(
@@ -613,4 +625,8 @@ void ScreenSpaceRenderable::draw(glm::mat4 modelTransform) {
void ScreenSpaceRenderable::unbindTexture() {}
float ScreenSpaceRenderable::opacity() const {
return _opacity * _fade;
}
} // namespace openspace
+4
View File
@@ -343,6 +343,10 @@ bool AssetManager::loadAsset(Asset* asset, Asset* parent) {
LERROR(fmt::format("Could not load asset {}: {}", asset->path(), e.message));
return false;
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
return false;
}
// Extract meta information from the asset file if it was provided
lua_getglobal(*_luaState, AssetGlobalVariableName);
+1 -1
View File
@@ -61,7 +61,7 @@ namespace {
* Returns the paths to all loaded assets, loaded directly or indirectly, as a table
* containing the paths to all loaded assets.
*/
[[codegen::luawrap]] std::vector<std::string> allAssets(std::string assetName) {
[[codegen::luawrap]] std::vector<std::string> allAssets() {
using namespace openspace;
std::vector<const Asset*> as = global::openSpaceEngine->assetManager().allAssets();
std::vector<std::string> res;
-6
View File
@@ -66,12 +66,6 @@ ghoul::mm_unique_ptr<Rotation> Rotation::createFromDictionary(
Rotation::Rotation() : properties::PropertyOwner({ "Rotation" }) {}
// @TODO (abock, 2021-03-25) This constructor can probably die since it doesn't do any
// above the default constructor
Rotation::Rotation(const ghoul::Dictionary&)
: properties::PropertyOwner({ "Rotation" })
{}
void Rotation::requireUpdate() {
_needsUpdate = true;
}
+1 -2
View File
@@ -715,8 +715,7 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) {
}
const bool visible = _renderable && _renderable->isVisible() &&
_renderable->isReady() && _renderable->isEnabled() &&
_renderable->matchesRenderBinMask(data.renderBinMask);
_renderable->isReady() && _renderable->matchesRenderBinMask(data.renderBinMask);
if (!visible) {
return;
+7 -7
View File
@@ -600,7 +600,7 @@ void ScriptEngine::preSync(bool isMaster) {
return;
}
std::lock_guard guard(_slaveScriptsMutex);
std::lock_guard guard(_clientScriptsMutex);
while (!_incomingScripts.empty()) {
QueueItem item = std::move(_incomingScripts.front());
_incomingScripts.pop();
@@ -634,14 +634,14 @@ void ScriptEngine::encode(SyncBuffer* syncBuffer) {
void ScriptEngine::decode(SyncBuffer* syncBuffer) {
ZoneScoped
std::lock_guard guard(_slaveScriptsMutex);
std::lock_guard guard(_clientScriptsMutex);
size_t nScripts;
syncBuffer->decode(nScripts);
for (size_t i = 0; i < nScripts; ++i) {
std::string script;
syncBuffer->decode(script);
_slaveScriptQueue.push(std::move(script));
_clientScriptQueue.push(std::move(script));
}
}
@@ -663,11 +663,11 @@ void ScriptEngine::postSync(bool isMaster) {
}
}
else {
std::lock_guard guard(_slaveScriptsMutex);
while (!_slaveScriptQueue.empty()) {
std::lock_guard guard(_clientScriptsMutex);
while (!_clientScriptQueue.empty()) {
try {
runScript(_slaveScriptQueue.front());
_slaveScriptQueue.pop();
runScript(_clientScriptQueue.front());
_clientScriptQueue.pop();
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
@@ -34,7 +34,7 @@ namespace {
OS os = CpuCap.operatingSystem();
switch (os) {
case OS::Windows10:
case OS::Windows10or11:
case OS::WindowsServer2016:
case OS::WindowsVista:
case OS::WindowsServer2008:
+11 -11
View File
@@ -896,24 +896,24 @@ bool TimeManager::isPlayingBackSessionRecording() const {
}
void TimeManager::setTimeFromProfile(const Profile& p) {
Time t;
if (p.time.has_value()) {
switch (p.time.value().type) {
case Profile::Time::Type::Relative:
t.setTimeRelativeFromProfile(p.time.value().value);
break;
case Profile::Time::Type::Relative:
Time::setTimeRelativeFromProfile(p.time.value().value);
break;
case Profile::Time::Type::Absolute:
t.setTimeAbsoluteFromProfile(p.time.value().value);
break;
case Profile::Time::Type::Absolute:
Time::setTimeAbsoluteFromProfile(p.time.value().value);
break;
default:
throw ghoul::MissingCaseException();
default:
throw ghoul::MissingCaseException();
}
}
else {
throw ghoul::RuntimeError("No 'time' entry exists in the startup profile");
// No value was specified so we are using 'now' instead
std::string now = std::string(Time::now().UTC());
Time::setTimeAbsoluteFromProfile(now);
}
}