mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-05-12 06:19:57 -05:00
merge with master
This commit is contained in:
@@ -50,7 +50,7 @@ TimeDialog::TimeDialog(QWidget* parent, std::optional<openspace::Profile::Time>*
|
||||
_timeData = **_time;
|
||||
if (_timeData.type == Profile::Time::Type::Relative) {
|
||||
if (_timeData.value == "") {
|
||||
_timeData.value = "now";
|
||||
_timeData.value = "0d";
|
||||
}
|
||||
_relativeEdit->setSelection(0, _relativeEdit->text().length());
|
||||
}
|
||||
@@ -60,7 +60,7 @@ TimeDialog::TimeDialog(QWidget* parent, std::optional<openspace::Profile::Time>*
|
||||
}
|
||||
else {
|
||||
_timeData.type = Profile::Time::Type::Relative;
|
||||
_timeData.value = "now";
|
||||
_timeData.value = "0d";
|
||||
}
|
||||
_initializedAsAbsolute = (_timeData.type == Profile::Time::Type::Absolute);
|
||||
enableAccordingToType(static_cast<int>(_timeData.type));
|
||||
@@ -114,7 +114,7 @@ void TimeDialog::enableAccordingToType(int idx) {
|
||||
if (comboIdx == Profile::Time::Type::Relative) {
|
||||
_relativeEdit->setText("<font color='black'>Relative Time:</font>");
|
||||
if (_initializedAsAbsolute) {
|
||||
_relativeEdit->setText("now");
|
||||
_relativeEdit->setText("0d");
|
||||
}
|
||||
else {
|
||||
_relativeEdit->setText(QString::fromStdString(_timeData.value));
|
||||
|
||||
+1
-1
Submodule apps/OpenSpace/ext/sgct updated: d89724510f...3f2bbf3ebb
@@ -0,0 +1,105 @@
|
||||
local toggle_trail = {
|
||||
Identifier = "os.toggle_trail",
|
||||
Name = "Toggle Trail",
|
||||
Command = [[
|
||||
local node
|
||||
if is_declared("args") then
|
||||
node = args.Node
|
||||
else
|
||||
node = openspace.navigation.getNavigationState().Anchor
|
||||
end
|
||||
|
||||
local trail
|
||||
if openspace.hasSceneGraphNode(node .. "Trail") then
|
||||
trail = node .. "Trail"
|
||||
elseif openspace.hasSceneGraphNode(node .. "_trail") then
|
||||
trail = node .. "_trail"
|
||||
else
|
||||
-- No trail found, so nothing more to do here
|
||||
return
|
||||
end
|
||||
|
||||
local visibility
|
||||
if is_declared("args") then
|
||||
if args.Transition == "Approaching" then
|
||||
visibility = false
|
||||
elseif args.Transition == "Exiting" then
|
||||
visibility = true
|
||||
else
|
||||
return
|
||||
end
|
||||
else
|
||||
visibility = not openspace.getPropertyValue("Scene." .. trail .. ".Renderable.Enabled")
|
||||
end
|
||||
|
||||
openspace.setPropertyValueSingle("Scene." .. trail .. ".Renderable.Enabled", visibility)
|
||||
]],
|
||||
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
|
||||
'Node') and 2) the transition direction (as 'After' and 'Before').]],
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("toggle_trail", toggle_trail.Identifier)
|
||||
|
||||
local hide_trail = {
|
||||
Identifier = "os.hide_trail",
|
||||
Name = "Hide Trail",
|
||||
Command = [[
|
||||
local node
|
||||
if is_declared("args") then
|
||||
node = args.Node
|
||||
else
|
||||
node = openspace.navigation.getNavigationState().Anchor
|
||||
end
|
||||
|
||||
if openspace.hasSceneGraphNode(node .. "Trail") then
|
||||
openspace.setPropertyValue("Scene." .. node .. "Trail.Renderable.Enabled", false)
|
||||
elseif openspace.hasSceneGraphNode(node .. "_trail") then
|
||||
openspace.setPropertyValue("Scene." .. node .. "_trail.Renderable.Enabled", false)
|
||||
end
|
||||
]],
|
||||
Documentation = [[Hides the associated trail of a scene graph node. This action takes an
|
||||
optional argument to determine whose trail to hide. If no argument is provided, the
|
||||
current focus node is used instead]],
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("hide_trail", hide_trail.Identifier)
|
||||
|
||||
local show_trail = {
|
||||
Identifier = "os.show_trail",
|
||||
Name = "Show Trail",
|
||||
Command = [[
|
||||
local node
|
||||
if is_declared("args") then
|
||||
node = args.Node
|
||||
else
|
||||
node = openspace.navigation.getNavigationState().Anchor
|
||||
end
|
||||
|
||||
if openspace.hasSceneGraphNode(node .. "Trail") then
|
||||
openspace.setPropertyValue("Scene." .. node .. "Trail.Renderable.Enabled", true)
|
||||
elseif openspace.hasSceneGraphNode(node .. "_trail") then
|
||||
openspace.setPropertyValue("Scene." .. node .. "_trail.Renderable.Enabled", true)
|
||||
end
|
||||
]],
|
||||
Documentation = [[Shows the associated trail of a scene graph node. This action takes an
|
||||
optional argument to determine whose trail to hide. If no argument is provided, the
|
||||
current focus node is used instead]],
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("show_trail", show_trail.Identifier)
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(toggle_trail)
|
||||
openspace.action.registerAction(show_trail)
|
||||
openspace.action.registerAction(hide_trail)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(toggle_trail.Identifier)
|
||||
openspace.action.removeAction(show_trail.Identifier)
|
||||
openspace.action.removeAction(hide_trail.Identifier)
|
||||
end)
|
||||
@@ -0,0 +1,27 @@
|
||||
local action = asset.require('actions/toggle_trail')
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.event.registerEventAction(
|
||||
"CameraFocusTransition",
|
||||
action.show_trail,
|
||||
{ Transition = "Exiting" }
|
||||
);
|
||||
openspace.event.registerEventAction(
|
||||
"CameraFocusTransition",
|
||||
action.hide_trail,
|
||||
{ Transition = "Approaching" }
|
||||
);
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.event.unregisterEventAction(
|
||||
"CameraFocusTransition",
|
||||
action.show_trail,
|
||||
{ Transition = "Exiting" }
|
||||
);
|
||||
openspace.event.unregisterEventAction(
|
||||
"CameraFocusTransition",
|
||||
action.hide_trail,
|
||||
{ Transition = "Approaching" }
|
||||
);
|
||||
end)
|
||||
@@ -0,0 +1,68 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
|
||||
local transforms = asset.require('scene/solarsystem/planets/earth/transforms')
|
||||
|
||||
local generic_action = {
|
||||
Identifier = "os.example.generic",
|
||||
Name = "Generic Example",
|
||||
Command = [[
|
||||
openspace.printInfo("Node: " .. args.Node)
|
||||
openspace.printInfo("Transition: " .. args.Transition)
|
||||
]],
|
||||
Documentation = "Prints the argument information for camera transitions to the log",
|
||||
GuiPath = "/Examples/Events",
|
||||
IsLocal = true
|
||||
}
|
||||
|
||||
local model = asset.syncedResource({
|
||||
Name = "Animated Box",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "animated_box",
|
||||
Version = 1
|
||||
})
|
||||
|
||||
local obj = {
|
||||
Identifier = "ExampleEventModel",
|
||||
Parent = transforms.EarthCenter.Identifier,
|
||||
Transform = {
|
||||
Translation = {
|
||||
Type = "StaticTranslation",
|
||||
Position = { 0.0, 11E7, 0.0 }
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
Type = "RenderableModel",
|
||||
GeometryFile = model .. "/BoxAnimated.glb",
|
||||
ModelScale = 1.0,
|
||||
LightSources = {
|
||||
{
|
||||
Type = "SceneGraphLightSource",
|
||||
Identifier = "Sun",
|
||||
Node = sunTransforms.SolarSystemBarycenter.Identifier,
|
||||
Intensity = 1.0
|
||||
}
|
||||
},
|
||||
PerformShading = true,
|
||||
DisableFaceCulling = true
|
||||
},
|
||||
InteractionSphere = 1000.0,
|
||||
OnApproach = { "os.example.generic" },
|
||||
OnReach = { "os.example.generic" },
|
||||
OnRecede = { "os.example.generic" },
|
||||
OnExit = { "os.example.generic" },
|
||||
GUI = {
|
||||
Name = "Example Event Model",
|
||||
Path = "/Example",
|
||||
Description = "",
|
||||
}
|
||||
}
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(generic_action)
|
||||
openspace.addSceneGraphNode(obj)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.removeSceneGraphNode(obj.Identifier)
|
||||
openspace.action.removeAction(generic_action.Identifier)
|
||||
end)
|
||||
+1
-1
Submodule ext/ghoul updated: 4b64684acd...874300a089
@@ -175,7 +175,7 @@ TestResult OperatorVerifier<T, Operator>::operator()(const ghoul::Dictionary& di
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -290,7 +290,7 @@ TestResult NotInListVerifier<T>::operator()(const ghoul::Dictionary& dict,
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -346,7 +346,7 @@ TestResult InRangeVerifier<T>::operator()(const ghoul::Dictionary& dict,
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -363,7 +363,7 @@ TestResult InRangeVerifier<T>::operator()(const ghoul::Dictionary& dict,
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -405,7 +405,7 @@ TestResult NotInRangeVerifier<T>::operator()(const ghoul::Dictionary& dict,
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -419,7 +419,7 @@ TestResult NotInRangeVerifier<T>::operator()(const ghoul::Dictionary& dict,
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
else {
|
||||
return { true, {}, {} };
|
||||
|
||||
@@ -89,6 +89,7 @@ struct Configuration {
|
||||
|
||||
bool isCheckingOpenGLState = false;
|
||||
bool isLoggingOpenGLCalls = false;
|
||||
bool isPrintingEvents = false;
|
||||
|
||||
float shutdownCountdown = 0.f;
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace openspace {
|
||||
class Dashboard;
|
||||
class DeferredcasterManager;
|
||||
class DownloadManager;
|
||||
class EventEngine;
|
||||
class LuaConsole;
|
||||
class MemoryManager;
|
||||
class MissionManager;
|
||||
@@ -74,6 +75,7 @@ inline ghoul::fontrendering::FontManager* fontManager;
|
||||
inline Dashboard* dashboard;
|
||||
inline DeferredcasterManager* deferredcasterManager;
|
||||
inline DownloadManager* downloadManager;
|
||||
inline EventEngine* eventEngine;
|
||||
inline LuaConsole* luaConsole;
|
||||
inline MemoryManager* memoryManager;
|
||||
inline MissionManager* missionManager;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#define __OPENSPACE_CORE___OPENSPACEENGINE___H__
|
||||
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <openspace/util/keys.h>
|
||||
#include <openspace/util/mouse.h>
|
||||
@@ -117,6 +118,8 @@ private:
|
||||
std::string generateFilePath(std::string openspaceRelativePath);
|
||||
void resetPropertyChangeFlagsOfSubowners(openspace::properties::PropertyOwner* po);
|
||||
|
||||
properties::BoolProperty _printEvents;
|
||||
|
||||
std::unique_ptr<Scene> _scene;
|
||||
std::unique_ptr<AssetManager> _assetManager;
|
||||
bool _shouldAbortLoading = false;
|
||||
|
||||
@@ -0,0 +1,395 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* 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___EVENT___H__
|
||||
#define __OPENSPACE_CORE___EVENT___H__
|
||||
|
||||
#include <openspace/util/tstring.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace properties { class Property; }
|
||||
|
||||
class Camera;
|
||||
class Layer;
|
||||
class Profile;
|
||||
class SceneGraphNode;
|
||||
class ScreenSpaceRenderable;
|
||||
class Time;
|
||||
} // namespace openspace
|
||||
|
||||
namespace openspace::events {
|
||||
|
||||
struct Event {
|
||||
// Steps to add a new event type:
|
||||
// 1. Add a new entry into this enum list
|
||||
// 2. Create a new subclass of Event in this file with a constructor that sets the
|
||||
// Event's `type` to this new enum entry
|
||||
// 3. In the cpp file, add a new `log` message that takes the new type as an argument
|
||||
// and that prints something useful when the log is encountered and the user wants
|
||||
// to see all events.
|
||||
// 4. Add a new case into the logAllEvents function that handles the new enum entry
|
||||
// 5. If the new event type has any parameters it takes in its constructor, go into
|
||||
// the `toParameter` function and add a case label for the new enum type and
|
||||
// return a dictionary with these parameters. This dictionary is passed to actions
|
||||
// if they are triggered by events
|
||||
// 6. Add the new enum entry into the `toString` and `fromString` methods
|
||||
enum class Type {
|
||||
SceneGraphNodeAdded,
|
||||
SceneGraphNodeRemoved,
|
||||
ParallelConnection,
|
||||
ProfileLoadingFinished,
|
||||
ApplicationShutdown,
|
||||
ScreenSpaceRenderableAdded,
|
||||
ScreenSpaceRenderableRemoved,
|
||||
CameraFocusTransition,
|
||||
TimeOfInterestReached,
|
||||
MissionEventReached,
|
||||
PlanetEclipsed,
|
||||
InterpolationFinished,
|
||||
FocusNodeChanged,
|
||||
LayerAdded,
|
||||
LayerRemoved,
|
||||
SessionRecordingPlayback,
|
||||
Custom
|
||||
};
|
||||
constexpr explicit Event(Type type_) : type(type_) {}
|
||||
|
||||
const Type type;
|
||||
const Event* next = nullptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T* asType(Event* e) {
|
||||
ghoul_assert(e->type == T::Type, "Wrong type requested, check 'isType'");
|
||||
return static_cast<T*>(e);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool isType(Event* e) {
|
||||
return e->type == T::Type;
|
||||
}
|
||||
|
||||
std::string_view toString(Event::Type type);
|
||||
Event::Type fromString(std::string_view str);
|
||||
|
||||
ghoul::Dictionary toParameter(const Event& e);
|
||||
|
||||
void logAllEvents(const Event* e);
|
||||
|
||||
//
|
||||
// Events
|
||||
//
|
||||
|
||||
/**
|
||||
* This event is created whenever a new scene graph node is added to the system. By the
|
||||
* time this event is signalled, the scene graph node has already been created and added
|
||||
* to the scene.
|
||||
*
|
||||
* \param Node The identifier of the node that was added
|
||||
*/
|
||||
struct EventSceneGraphNodeAdded : public Event {
|
||||
static const Type Type = Event::Type::SceneGraphNodeAdded;
|
||||
|
||||
explicit EventSceneGraphNodeAdded(const SceneGraphNode* node_);
|
||||
const tstring node;
|
||||
};
|
||||
|
||||
/**
|
||||
* This event is created whenever a scene graph node was removed. By the time this event
|
||||
* is signalled, the scene graph node has already been removed.
|
||||
*
|
||||
* \param Node The identifier of that node that was removed
|
||||
*/
|
||||
struct EventSceneGraphNodeRemoved : public Event {
|
||||
static const Type Type = Event::Type::SceneGraphNodeRemoved;
|
||||
|
||||
explicit EventSceneGraphNodeRemoved(const SceneGraphNode* node_);
|
||||
const tstring node;
|
||||
};
|
||||
|
||||
/**
|
||||
* This event is created whenever something in the parallel connection subsystem changes.
|
||||
* The new state is sent as an argument with this event.
|
||||
*
|
||||
* \param State The new state of the parallel connection system; is one of `Established`,
|
||||
* `Lost`, `HostshipGained`, or `HostshipLost`
|
||||
*/
|
||||
struct EventParallelConnection : public Event {
|
||||
static const Type Type = Event::Type::ParallelConnection;
|
||||
|
||||
enum class State : uint8_t {
|
||||
Established,
|
||||
Lost,
|
||||
HostshipGained,
|
||||
HostshipLost
|
||||
};
|
||||
explicit EventParallelConnection(State state_);
|
||||
State state;
|
||||
};
|
||||
|
||||
/**
|
||||
* This event is created when the loading of a profile is finished. This is emitted
|
||||
* regardless of whether it is the initial profile, or any subsequent profile is loaded.
|
||||
*/
|
||||
struct EventProfileLoadingFinished : public Event {
|
||||
static const Type Type = Event::Type::ProfileLoadingFinished;
|
||||
|
||||
EventProfileLoadingFinished();
|
||||
};
|
||||
|
||||
/**
|
||||
* This event is created whenever some information about the application shutdown sequence
|
||||
* changes. This can either be that the seqeuence started, was aborted, or is finished,
|
||||
* which means that OpenSpace is just about the shutdown.
|
||||
*
|
||||
* \param State The next state of the application shutdown sequence; is one of `Started`,
|
||||
* `Aborted`, or `Finished`
|
||||
*/
|
||||
struct EventApplicationShutdown : public Event {
|
||||
static const Type Type = Event::Type::ApplicationShutdown;
|
||||
|
||||
enum class State : uint8_t {
|
||||
Started,
|
||||
Aborted,
|
||||
Finished
|
||||
};
|
||||
|
||||
explicit EventApplicationShutdown(State state_);
|
||||
const State state;
|
||||
};
|
||||
|
||||
/**
|
||||
* This event is created when a new screenspace renderable has been created. By the time
|
||||
* this event is craeted, the screenspace renderable is already registered and available.
|
||||
*
|
||||
* \param Renderable The identifier of the new screenspace renderable that was just added
|
||||
* to the system
|
||||
*/
|
||||
struct EventScreenSpaceRenderableAdded : public Event {
|
||||
static const Type Type = Event::Type::ScreenSpaceRenderableAdded;
|
||||
|
||||
explicit EventScreenSpaceRenderableAdded(const ScreenSpaceRenderable* renderable_);
|
||||
const tstring renderable;
|
||||
};
|
||||
|
||||
/**
|
||||
* This event is created when a screenspace renderable has been removed from the system.
|
||||
* When this event is created, the screenspace renderable has already been removed and is
|
||||
* no longer available
|
||||
*
|
||||
* \param Renderable The identifier of the screenspace renderable that was removed
|
||||
*/
|
||||
struct EventScreenSpaceRenderableRemoved : public Event {
|
||||
static const Type Type = Event::Type::ScreenSpaceRenderableRemoved;
|
||||
|
||||
explicit EventScreenSpaceRenderableRemoved(const ScreenSpaceRenderable* renderable_);
|
||||
const tstring renderable;
|
||||
};
|
||||
|
||||
/**
|
||||
* This event is created when the camera transitions between different interaction sphere
|
||||
* distances. Right now, only movement relative to camera's focus node is considered.
|
||||
* Each scene graph node has an interaction sphere radius that serves as the reference
|
||||
* distance for all spheres.
|
||||
```
|
||||
Diagram of events for a camera moving from right-to-left. Interaction sphere is 'O' in
|
||||
middle, and ')' are spherical boundaries. The approach factor, reach factor, and
|
||||
interaction sphere radius are all taken from the current focus node.
|
||||
|
||||
|<------------------->| Approach factor * Interaction sphere
|
||||
|<------>| Reach Factor * Interaction sphere
|
||||
|
||||
( ( O ) )
|
||||
^ ^ ^ ^
|
||||
Exiting Receding Reaching Approaching
|
||||
```
|
||||
*
|
||||
* \param Node The name of the node the camera is transitioning relative to. Currently is
|
||||
* always the same as the camera's focus node
|
||||
* \param Transition The transition type that the camera just finished; is one of
|
||||
* `Approaching`, `Reaching`, `Receding`, or `Exiting`
|
||||
*/
|
||||
struct EventCameraFocusTransition : public Event {
|
||||
static const Type Type = Event::Type::CameraFocusTransition;
|
||||
|
||||
enum class Transition {
|
||||
Approaching,
|
||||
Reaching,
|
||||
Receding,
|
||||
Exiting
|
||||
};
|
||||
|
||||
EventCameraFocusTransition(const Camera* camera_, const SceneGraphNode* node_,
|
||||
Transition transition_);
|
||||
|
||||
const Camera* camera = nullptr;
|
||||
const tstring node;
|
||||
const Transition transition;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This event is created with a specific time of interest is reached. This event is
|
||||
* currently unused.
|
||||
*/
|
||||
struct EventTimeOfInterestReached : public Event {
|
||||
static const Type Type = Event::Type::TimeOfInterestReached;
|
||||
|
||||
EventTimeOfInterestReached(const Time* time_, const Camera* camera_);
|
||||
const Time* time = nullptr;
|
||||
const Camera* camera = nullptr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This event is created when the end of a mission phase is reached. This event is
|
||||
* currently unused.
|
||||
*/
|
||||
struct EventMissionEventReached : public Event {
|
||||
static const Type Type = Event::Type::MissionEventReached;
|
||||
|
||||
// Not sure which kind of parameters we want to pass here
|
||||
EventMissionEventReached();
|
||||
};
|
||||
|
||||
/**
|
||||
* This event is created when a planet is eclipsed by a moon or a different planet. This
|
||||
* event is currently unused.
|
||||
*
|
||||
* \param Eclipsee The identifier of the scene graph node that is eclipsed by another
|
||||
* object
|
||||
* \param Eclipser The identifier of the scene graph node that is eclipsing the other
|
||||
* object
|
||||
*/
|
||||
struct EventPlanetEclipsed : public Event {
|
||||
static const Type Type = Event::Type::PlanetEclipsed;
|
||||
|
||||
EventPlanetEclipsed(const SceneGraphNode* eclipsee_, const SceneGraphNode* eclipser_);
|
||||
const tstring eclipsee;
|
||||
const tstring eclipser;
|
||||
};
|
||||
|
||||
/**
|
||||
* This event is created when the interpolation of a property value is finished. If the
|
||||
* interpolation time of a property change is 0s, this event is not fired
|
||||
*
|
||||
* \param Property The URI of the property whose interpolation has finished
|
||||
*/
|
||||
struct EventInterpolationFinished : public Event {
|
||||
static const Type Type = Event::Type::InterpolationFinished;
|
||||
|
||||
EventInterpolationFinished(const properties::Property* property_);
|
||||
const tstring property;
|
||||
};
|
||||
|
||||
/**
|
||||
* This event is created when the camera changes focus nodes. Even if the camera position
|
||||
* is interpolated, the node change happens instantaneously and the event is fired at the
|
||||
* same time.
|
||||
*
|
||||
* \param OldNode The identifier of the scene graph node which was the old focus node
|
||||
* \param NewNode The identifier of the scene graph node that is the new focus node
|
||||
*/
|
||||
struct EventFocusNodeChanged : public Event {
|
||||
static const Type Type = Event::Type::FocusNodeChanged;
|
||||
|
||||
EventFocusNodeChanged(const SceneGraphNode* oldNode_, const SceneGraphNode* newNode_);
|
||||
const tstring oldNode;
|
||||
const tstring newNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* This event is created when a layer is added to to a globe.
|
||||
*
|
||||
* \param Globe The identifier of the globe to which the layer is added
|
||||
* \param Group The identifier of the layer group to which the layer is added
|
||||
* \param Layer The identifier of the layer that was added
|
||||
*/
|
||||
struct EventLayerAdded : public Event {
|
||||
static const Type Type = Event::Type::LayerAdded;
|
||||
|
||||
explicit EventLayerAdded(std::string_view node_, std::string_view layerGroup_,
|
||||
std::string_view layer_);
|
||||
const tstring node;
|
||||
const tstring layerGroup;
|
||||
const tstring layer;
|
||||
};
|
||||
|
||||
/**
|
||||
* This event is created when a layer is removed from a globe.
|
||||
*
|
||||
* \param Globe The identifier of the globe from which the layer is removed
|
||||
* \param Group The identifier of the layer group from which the layer is removed
|
||||
* \param Layer The identifier of the layer that was removed
|
||||
*/
|
||||
struct EventLayerRemoved : public Event {
|
||||
static const Type Type = Event::Type::LayerRemoved;
|
||||
|
||||
explicit EventLayerRemoved(std::string_view node_, std::string_view layerGroup_,
|
||||
std::string_view layer_);
|
||||
const tstring node;
|
||||
const tstring layerGroup;
|
||||
const tstring layer;
|
||||
};
|
||||
|
||||
/**
|
||||
* This event is created when something regarding a session recording playback changes.
|
||||
* The event contains information about the new state of the session recording subsystem.
|
||||
*
|
||||
* \param State The new state of the session recording; one of `Started`, `Paused`,
|
||||
* `Resumed`, `Finished`
|
||||
*/
|
||||
struct EventSessionRecordingPlayback : public Event {
|
||||
static const Type Type = Event::Type::SessionRecordingPlayback;
|
||||
|
||||
enum class State {
|
||||
Started,
|
||||
Paused,
|
||||
Resumed,
|
||||
Finished
|
||||
};
|
||||
|
||||
EventSessionRecordingPlayback(State state_);
|
||||
const State state;
|
||||
};
|
||||
|
||||
/**
|
||||
* A custom event type that can be used in a pinch when no explicit event type is
|
||||
* available. This should only be used in special circumstances and it should be
|
||||
* transitioned to a specific event type, if it is deemed to be useful.
|
||||
*/
|
||||
struct CustomEvent : public Event {
|
||||
static const Type Type = Event::Type::Custom;
|
||||
|
||||
CustomEvent(std::string_view subtype_, const void* payload_);
|
||||
|
||||
const tstring subtype;
|
||||
const void* payload = nullptr;
|
||||
};
|
||||
|
||||
} // namespace openspace::events
|
||||
|
||||
#endif // __OPENSPACE_CORE___EVENT___H__
|
||||
@@ -0,0 +1,125 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* 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___EVENTENGINE___H__
|
||||
#define __OPENSPACE_CORE___EVENTENGINE___H__
|
||||
|
||||
#include <openspace/events/event.h>
|
||||
#include <openspace/scripting/lualibrary.h>
|
||||
#include <ghoul/misc/memorypool.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace events { struct Event; }
|
||||
|
||||
class EventEngine {
|
||||
public:
|
||||
/**
|
||||
* This function returns the first event stored in the EventEngine, or \c nullptr if
|
||||
* no event exists. To navigate the full list of events, you can access the returned
|
||||
* Event's next function. If the end of the list is reached, the next pointer will be
|
||||
* a nullptr
|
||||
*
|
||||
* \return The first event stored in the EventEngine or nullptr if no event exists
|
||||
*/
|
||||
events::Event* firstEvent() const;
|
||||
|
||||
/**
|
||||
* Publish a new event of type T by providing optional arguments Args to the Event's
|
||||
* constructor. An example of usage is
|
||||
* <code>engine.publishEvent<MyEvent>("a", 2.0);</code> which would call the
|
||||
* constructor of \c MyEvent with a <code>const char*</code> and \c double parameter.
|
||||
*
|
||||
* \param args The arguments that are passed to the constructor of T
|
||||
* \tparam T The subclass of Event that is to be published
|
||||
*/
|
||||
template <typename T, typename... Args>
|
||||
void publishEvent(Args&&... args);
|
||||
|
||||
/**
|
||||
* This function cleans up the memory for all published events.After this function
|
||||
* has been called, no previously published events are valid any longer. This means
|
||||
* that pointers retrieved from events before this call must be kept beyond this call.
|
||||
*/
|
||||
void postFrameCleanup();
|
||||
|
||||
/**
|
||||
* Registers a new action for a specific event type.
|
||||
*
|
||||
* \param type The type for which a new action is registered
|
||||
* \param actionIdentifier The identifier of the action that will be triggered the
|
||||
* identifier must not exist at this moment, but must exist by the time the
|
||||
* event is encountered next
|
||||
* \param filter If the filter is provided, it describes the event parameters that are
|
||||
* checked and only if an event passes the filter, the corresponding action is
|
||||
* triggered
|
||||
*/
|
||||
void registerEventAction(events::Event::Type type, std::string identifier,
|
||||
std::optional<ghoul::Dictionary> filter = std::nullopt);
|
||||
|
||||
/**
|
||||
* Removing registration for a type/action combination.
|
||||
*
|
||||
* \param type The type of the action that should be unregistered
|
||||
* \param actionIdentifier The identifier of the action that should be unregistered
|
||||
* \param filter The optional filter applied to the event-action combination
|
||||
*/
|
||||
void unregisterEventAction(events::Event::Type type,
|
||||
const std::string& identifier,
|
||||
std::optional<ghoul::Dictionary> filter = std::nullopt);
|
||||
|
||||
/**
|
||||
* Triggers all actions that are registered for events that are in the current event
|
||||
* queue
|
||||
*/
|
||||
void triggerActions() const;
|
||||
|
||||
static scripting::LuaLibrary luaLibrary();
|
||||
|
||||
private:
|
||||
/// The storage space in which Events are stored
|
||||
ghoul::MemoryPool<4096> _memory;
|
||||
/// The first event in the chain of events stored in the memory pool
|
||||
events::Event* _firstEvent = nullptr;
|
||||
/// The last event in the chain of events stored in the memory pool
|
||||
events::Event* _lastEvent = nullptr;
|
||||
|
||||
struct ActionInfo {
|
||||
std::string action;
|
||||
std::optional<ghoul::Dictionary> filter;
|
||||
};
|
||||
std::unordered_map<events::Event::Type, std::vector<ActionInfo>> _eventActions;
|
||||
|
||||
#ifdef _DEBUG
|
||||
/// Stores the total number of events during this frame for debugging purposes
|
||||
static uint64_t nEvents;
|
||||
#endif // _DEBUG
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#include "eventengine.inl"
|
||||
|
||||
#endif // __OPENSPACE_CORE___EVENTENGINE___H__
|
||||
@@ -0,0 +1,51 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* 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 <type_traits>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
template <typename T, typename... Args>
|
||||
void EventEngine::publishEvent(Args&&... args) {
|
||||
static_assert(
|
||||
std::is_base_of<events::Event, T>::value,
|
||||
"T must be a subclass of Event"
|
||||
);
|
||||
|
||||
T* e = _memory.alloc<T>(args...);
|
||||
if (!_firstEvent) {
|
||||
_firstEvent = e;
|
||||
_lastEvent = e;
|
||||
}
|
||||
else {
|
||||
_lastEvent->next = e;
|
||||
_lastEvent = e;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
nEvents++;
|
||||
#endif // _DEBUG
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
@@ -140,6 +140,7 @@ public:
|
||||
|
||||
private:
|
||||
void applyNavigationState(const NavigationState& ns);
|
||||
void updateCameraTransitions();
|
||||
|
||||
bool _playbackModeEnabled = false;
|
||||
|
||||
@@ -147,6 +148,10 @@ private:
|
||||
Camera* _camera = nullptr;
|
||||
std::function<void()> _playbackEndCallback;
|
||||
|
||||
inline static const double InteractionHystersis = 0.0125;
|
||||
bool _inAnchorApproachSphere = false;
|
||||
bool _inAnchorReachSphere = false;
|
||||
|
||||
OrbitalNavigator _orbitalNavigator;
|
||||
KeyframeNavigator _keyframeNavigator;
|
||||
PathNavigator _pathNavigator;
|
||||
|
||||
@@ -371,10 +371,10 @@ private:
|
||||
|
||||
/**
|
||||
* Orbit the current anchor node, in a right-bound orbit, by updating the position
|
||||
* and global rotation of the camera.
|
||||
*
|
||||
* and global rotation of the camera.
|
||||
*
|
||||
* Used for IdleBehavior::Behavior::Orbit
|
||||
*
|
||||
*
|
||||
* \param deltaTime The time step to use for the motion. Controls the rotation angle
|
||||
* \param position The position of the camera. Will be changed by the function
|
||||
* \param globalRotation The camera's global rotation. Will be changed by the function
|
||||
@@ -384,15 +384,15 @@ private:
|
||||
glm::dquat& globalRotation, double speedScale);
|
||||
|
||||
/**
|
||||
* Orbit the current anchor node, by adding a rotation around the given axis. For
|
||||
* example, when the axis is the north vector, the camera will stay on the current
|
||||
* latitude band. Note that this creates a rolling motion if the camera's forward
|
||||
* vector coincides with the axis, and should be used with care.
|
||||
*
|
||||
* Orbit the current anchor node, by adding a rotation around the given axis. For
|
||||
* example, when the axis is the north vector, the camera will stay on the current
|
||||
* latitude band. Note that this creates a rolling motion if the camera's forward
|
||||
* vector coincides with the axis, and should be used with care.
|
||||
*
|
||||
* Used for:
|
||||
* IdleBehavior::Behavior::OrbitAtConstantLat ( axis = north = z-axis ) and
|
||||
* IdleBehavior::Behavior::OrbitAroundUp ( axis = up = y-axis )
|
||||
*
|
||||
*
|
||||
* \param axis The axis to arbit around, given in model coordinates of the anchor
|
||||
* \param deltaTime The time step to use for the motion. Controls the rotation angle
|
||||
* \param position The position of the camera. Will be changed by the function
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace openspace {
|
||||
struct CameraPose;
|
||||
namespace openspace {
|
||||
struct CameraPose;
|
||||
} // namespace openspace
|
||||
|
||||
namespace openspace::interaction {
|
||||
@@ -44,10 +44,10 @@ public:
|
||||
Linear,
|
||||
ZoomOutOverview,
|
||||
AvoidCollisionWithLookAt // @TODO (2021-08-13, emmbr) This type right now leads
|
||||
// to rapid rotations, but is useful in specific
|
||||
// scenarios, e.g. close to surfaces. Later we want to
|
||||
// to rapid rotations, but is useful in specific
|
||||
// scenarios, e.g. close to surfaces. Later we want to
|
||||
// remove it, and create a curve type that looks nicely
|
||||
// at the targets when moving, avoids collisions and
|
||||
// at the targets when moving, avoids collisions and
|
||||
// doesn't introduce sudden large changes in rotation
|
||||
};
|
||||
|
||||
@@ -63,21 +63,21 @@ public:
|
||||
double pathLength() const;
|
||||
|
||||
/**
|
||||
* Return a vector of positions corresponding to the control points of the path's
|
||||
* Return a vector of positions corresponding to the control points of the path's
|
||||
* spline curve
|
||||
*/
|
||||
std::vector<glm::dvec3> controlPoints() const;
|
||||
|
||||
/**
|
||||
* Take a step along the current path, corresponding to the delta time step \p dt, and
|
||||
* return the resulting camera pose. The \p speedScale is a factor that will be
|
||||
* return the resulting camera pose. The \p speedScale is a factor that will be
|
||||
* multiplied with the traversal speed
|
||||
*/
|
||||
CameraPose traversePath(double dt, float speedScale = 1.f);
|
||||
|
||||
/**
|
||||
* Return the identifer of the node that is the current appropriate anchor node, of
|
||||
* the start and end waypoint's reference node. Dtermined based on how far along the
|
||||
* Return the identifer of the node that is the current appropriate anchor node, of
|
||||
* the start and end waypoint's reference node. Dtermined based on how far along the
|
||||
* path we have traveled
|
||||
*/
|
||||
std::string currentAnchor() const;
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
|
||||
private:
|
||||
/**
|
||||
* Interpolate between the paths start and end rotation using the approach that
|
||||
* Interpolate between the paths start and end rotation using the approach that
|
||||
* corresponds to the path's curve type. The interpolation parameter \p t is the
|
||||
* same as for the position interpolation, i.e. the relative traveled in distance
|
||||
* along the path, in [0, 1]
|
||||
@@ -107,14 +107,14 @@ private:
|
||||
glm::dquat easedSlerpRotation(double t) const;
|
||||
|
||||
/**
|
||||
* Compute the interpolated rotation quaternion using an approach that first
|
||||
* interpolates to look at the start node, and then the end node, before
|
||||
* Compute the interpolated rotation quaternion using an approach that first
|
||||
* interpolates to look at the start node, and then the end node, before
|
||||
* interpolating to the end rotation
|
||||
*/
|
||||
glm::dquat lookAtTargetsRotation(double t) const;
|
||||
|
||||
/**
|
||||
* Evaluate the current traversal speed along the path, based on the currently
|
||||
* Evaluate the current traversal speed along the path, based on the currently
|
||||
* traveled distance. The final speed will be scaled to match the desired duration
|
||||
* for the path (which might have been specified by the user)
|
||||
*/
|
||||
@@ -134,9 +134,9 @@ private:
|
||||
};
|
||||
|
||||
|
||||
// Create a path of the given type based on an instruction given as a dictionary.
|
||||
// See top of cpp file for documentation on keys and values for the dictionary.
|
||||
// Returns the created path.
|
||||
// Create a path of the given type based on an instruction given as a dictionary.
|
||||
// See top of cpp file for documentation on keys and values for the dictionary.
|
||||
// Returns the created path.
|
||||
Path createPathFromDictionary(const ghoul::Dictionary& dictionary, Path::Type type);
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
@@ -46,9 +46,9 @@ public:
|
||||
glm::dvec3 positionAt(double relativeDistance) const;
|
||||
|
||||
/**
|
||||
* Get the intorlatied position along the spline, based on the given curve parameter
|
||||
* u in range [0, 1]. A curve parameter of 0 returns the start position and 1 the end
|
||||
* position. Note that u does not correspond to the relatively traveled distance.
|
||||
* Get the intorlatied position along the spline, based on the given curve parameter
|
||||
* u in range [0, 1]. A curve parameter of 0 returns the start position and 1 the end
|
||||
* position. Note that u does not correspond to the relatively traveled distance.
|
||||
*/
|
||||
virtual glm::dvec3 interpolate(double u) const;
|
||||
|
||||
|
||||
@@ -45,4 +45,4 @@ private:
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
#endif // __OPENSPACE_MODULE_AUTONAVIGATION___AVOIDCOLLISIONCURVE___H__
|
||||
#endif // __OPENSPACE_CORE___AVOIDCOLLISIONCURVE___H__
|
||||
|
||||
@@ -53,7 +53,8 @@ public:
|
||||
private:
|
||||
CameraPose _pose;
|
||||
std::string _nodeIdentifier;
|
||||
double _validBoundingSphere = 0.0; // to be able to handle nodes with faulty bounding spheres
|
||||
// to be able to handle nodes with faulty bounding spheres
|
||||
double _validBoundingSphere = 0.0;
|
||||
};
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
@@ -114,7 +114,8 @@ public:
|
||||
using TemplateProperty<std::set<std::string>>::operator=;
|
||||
|
||||
protected:
|
||||
std::set<std::string> fromLuaConversion(lua_State* state, bool& success) const override;
|
||||
std::set<std::string> fromLuaConversion(lua_State* state,
|
||||
bool& success) const override;
|
||||
|
||||
void toLuaConversion(lua_State* state) const override;
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
|
||||
const glm::dmat3& matrix() const;
|
||||
virtual glm::dmat3 matrix(const UpdateData& time) const = 0;
|
||||
void update(const UpdateData& data);
|
||||
virtual void update(const UpdateData& data);
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <ghoul/misc/easing.h>
|
||||
#include <ghoul/misc/exception.h>
|
||||
#include <ghoul/misc/memorypool.h>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
@@ -46,6 +47,15 @@ namespace openspace {
|
||||
namespace documentation { struct Documentation; }
|
||||
namespace scripting { struct LuaLibrary; }
|
||||
|
||||
enum class PropertyValueType {
|
||||
Boolean = 0,
|
||||
Float,
|
||||
String,
|
||||
Table,
|
||||
Nil
|
||||
};
|
||||
using ProfilePropertyLua = std::variant<bool, float, std::string, ghoul::lua::nil_t>;
|
||||
|
||||
class SceneInitializer;
|
||||
|
||||
// Notifications:
|
||||
@@ -246,6 +256,59 @@ public:
|
||||
void setPropertiesFromProfile(const Profile& p);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Accepts string version of a property value from a profile, converts it to the
|
||||
* appropriate type, and then pushes the value onto the lua state.
|
||||
*
|
||||
* \param L the lua state to push value to
|
||||
* \param value string representation of the value with which to set property
|
||||
*/
|
||||
void propertyPushProfileValueToLua(ghoul::lua::LuaState& L, const std::string& value);
|
||||
|
||||
/**
|
||||
* Accepts string version of a property value from a profile, and processes it
|
||||
* according to the data type of the value
|
||||
*
|
||||
* \param L the lua state to (eventually) push to
|
||||
* \param value string representation of the value with which to set property
|
||||
* \param didPushToLua Bool reference that represents the lua push state at the end
|
||||
* of this function call. This will be set to true if the value (e.g. table)
|
||||
* has already been pushed to the lua stack
|
||||
* \return The ProfilePropertyLua variant type translated from string representation
|
||||
*/
|
||||
ProfilePropertyLua propertyProcessValue(ghoul::lua::LuaState& L,
|
||||
const std::string& value);
|
||||
|
||||
/**
|
||||
* Accepts string version of a property value from a profile, and returns the
|
||||
* supported data types that can be pushed to a lua state. Currently, the full
|
||||
* range of possible lua values is not supported.
|
||||
*
|
||||
* \param value string representation of the value with which to set property
|
||||
*/
|
||||
PropertyValueType propertyValueType(const std::string& value);
|
||||
|
||||
/**
|
||||
* Accepts string version of a property value from a profile, and adds it to a vector
|
||||
* which will later be used to push as a lua table containing values of type T
|
||||
*
|
||||
* \param L the lua state to (eventually) push to
|
||||
* \param value string representation of the value with which to set property
|
||||
* \param table the std::vector container which has elements of type T for a lua table
|
||||
*/
|
||||
template <typename T>
|
||||
void processPropertyValueTableEntries(ghoul::lua::LuaState& L,
|
||||
const std::string& value, std::vector<T>& table);
|
||||
|
||||
/**
|
||||
* Handles a lua table entry, creating a vector of the correct variable type based
|
||||
* on the profile string, and pushes this vector to the lua stack.
|
||||
*
|
||||
* \param L the lua state to (eventually) push to
|
||||
* \param value string representation of the value with which to set property
|
||||
*/
|
||||
void handlePropertyLuaTableEntry(ghoul::lua::LuaState& L, const std::string& value);
|
||||
|
||||
/**
|
||||
* Update dependencies.
|
||||
*/
|
||||
@@ -260,8 +323,9 @@ private:
|
||||
bool _dirtyNodeRegistry = false;
|
||||
SceneGraphNode _rootDummy;
|
||||
std::unique_ptr<SceneInitializer> _initializer;
|
||||
|
||||
std::string _profilePropertyName;
|
||||
std::vector<InterestingTime> _interestingTimes;
|
||||
bool _valueIsTable = false;
|
||||
|
||||
std::mutex _programUpdateLock;
|
||||
std::set<ghoul::opengl::ProgramObject*> _programsToUpdate;
|
||||
@@ -279,16 +343,6 @@ private:
|
||||
ghoul::MemoryPool<4096> _memoryPool;
|
||||
};
|
||||
|
||||
/**
|
||||
* Accepts string version of a property value from a profile, converts it to the
|
||||
* appropriate type, and then pushes the value onto the lua state.
|
||||
*
|
||||
* \param L the lua state to push value to
|
||||
* \param value string representation of the value with which to set property
|
||||
*/
|
||||
void propertyPushValueFromProfileToLuaState(ghoul::lua::LuaState& L,
|
||||
const std::string& value);
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___SCENE___H__
|
||||
|
||||
@@ -128,9 +128,17 @@ public:
|
||||
SceneGraphNode* parent() const;
|
||||
std::vector<SceneGraphNode*> children() const;
|
||||
|
||||
const std::vector<std::string>& onApproachAction() const;
|
||||
const std::vector<std::string>& onReachAction() const;
|
||||
const std::vector<std::string>& onRecedeAction() const;
|
||||
const std::vector<std::string>& onExitAction() const;
|
||||
|
||||
double boundingSphere() const;
|
||||
double interactionSphere() const;
|
||||
|
||||
double reachFactor() const;
|
||||
double approachFactor() const;
|
||||
|
||||
SceneGraphNode* childNode(const std::string& identifier);
|
||||
|
||||
const Renderable* renderable() const;
|
||||
@@ -155,6 +163,11 @@ private:
|
||||
std::vector<SceneGraphNode*> _dependentNodes;
|
||||
Scene* _scene = nullptr;
|
||||
|
||||
std::vector<std::string> _onApproachAction;
|
||||
std::vector<std::string> _onReachAction;
|
||||
std::vector<std::string> _onRecedeAction;
|
||||
std::vector<std::string> _onExitAction;
|
||||
|
||||
// If this value is 'true' GUIs are asked to hide this node from collections, as it
|
||||
// might be a node that is not very interesting (for example barycenters)
|
||||
properties::BoolProperty _guiHidden;
|
||||
@@ -183,6 +196,8 @@ private:
|
||||
|
||||
properties::DoubleProperty _boundingSphere;
|
||||
properties::DoubleProperty _interactionSphere;
|
||||
properties::DoubleProperty _approachFactor;
|
||||
properties::DoubleProperty _reachFactor;
|
||||
properties::BoolProperty _computeScreenSpaceValues;
|
||||
properties::IVec2Property _screenSpacePosition;
|
||||
properties::BoolProperty _screenVisibility;
|
||||
|
||||
@@ -50,8 +50,8 @@ public:
|
||||
virtual ~Translation() = default;
|
||||
virtual bool initialize();
|
||||
|
||||
virtual void update(const UpdateData& data);
|
||||
glm::dvec3 position() const;
|
||||
void update(const UpdateData& data);
|
||||
|
||||
virtual glm::dvec3 position(const UpdateData& data) const = 0;
|
||||
|
||||
|
||||
@@ -357,7 +357,9 @@ constexpr double convertUnit(DistanceUnit fromUnit, DistanceUnit toUnit) {
|
||||
return convertMeters(toMeter(fromUnit), toUnit);
|
||||
}
|
||||
|
||||
constexpr double convertDistance(double distance, DistanceUnit fromUnit, DistanceUnit toUnit) {
|
||||
constexpr double convertDistance(double distance, DistanceUnit fromUnit,
|
||||
DistanceUnit toUnit)
|
||||
{
|
||||
return distance * convertUnit(fromUnit, toUnit);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,11 +31,11 @@ namespace openspace {
|
||||
|
||||
class MemoryManager {
|
||||
public:
|
||||
ghoul::MemoryPool<8 * 1024 * 1024, false> PersistentMemory;
|
||||
ghoul::MemoryPool<8 * 1024 * 1024> PersistentMemory;
|
||||
|
||||
// This should be replaced with a std::pmr::memory_resource wrapper around our own
|
||||
// Memory pool so that we can get a high-water mark out of it
|
||||
ghoul::MemoryPool<100 * 4096, false> TemporaryMemory;
|
||||
ghoul::MemoryPool<100 * 4096, false, true> TemporaryMemory;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* 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___TSTRING___H__
|
||||
#define __OPENSPACE_CORE___TSTRING___H__
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
/**
|
||||
* This string is a temporary string that is generated using the temporary memory
|
||||
* storage. This means that under no circumstances must an instance of a tstring be kept
|
||||
* across frame boundaries as the temporary storage is reset at between frames. In
|
||||
* exchange, the allocation of these objects is extreme fast and with barely any overhead
|
||||
* associated with it. The memory accessed through a tstring object shall never be
|
||||
* released manually.
|
||||
*/
|
||||
using tstring = std::string_view;
|
||||
|
||||
/**
|
||||
* Allocate and create a temporary string from the passed std::string.
|
||||
*
|
||||
* \param str The string to be copied into a newly allocated tstring
|
||||
* \return The copy of the str as a temporary string
|
||||
*/
|
||||
tstring temporaryString(const std::string& str);
|
||||
|
||||
/**
|
||||
* Allocate and create a temporary string from the passed std::string_view.
|
||||
*
|
||||
* \param str The string to be copied into a newly allocated tstring
|
||||
* \return The copy of the str as a temporary string
|
||||
*/
|
||||
tstring temporaryString(std::string_view str);
|
||||
|
||||
/**
|
||||
* Allocate and create a temporary string from the passed char array.
|
||||
*
|
||||
* \param str The string to be copied into a newly allocated tstring
|
||||
* \return The copy of the str as a temporary string
|
||||
*/
|
||||
tstring temporaryString(const char str[]);
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___TSTRING___H__
|
||||
@@ -498,7 +498,7 @@ void AtmosphereDeferredcaster::setParameters(float atmosphereRadius, float plane
|
||||
float averageGroundReflectance,
|
||||
float groundRadianceEmission,
|
||||
float rayleighHeightScale, bool enableOzone,
|
||||
float ozoneHeightScale, float mieHeightScale,
|
||||
float ozoneHeightScale, float mieHeightScale,
|
||||
float miePhaseConstant, float sunRadiance,
|
||||
glm::vec3 rayScatteringCoefficients,
|
||||
glm::vec3 ozoneExtinctionCoefficients,
|
||||
@@ -529,7 +529,7 @@ void AtmosphereDeferredcaster::setHardShadows(bool enabled) {
|
||||
|
||||
void AtmosphereDeferredcaster::calculateTransmittance() {
|
||||
ZoneScoped
|
||||
|
||||
|
||||
glFramebufferTexture(
|
||||
GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
@@ -566,7 +566,7 @@ void AtmosphereDeferredcaster::calculateTransmittance() {
|
||||
|
||||
GLuint AtmosphereDeferredcaster::calculateDeltaE() {
|
||||
ZoneScoped
|
||||
|
||||
|
||||
GLuint deltaE = createTexture(_deltaETableSize, "DeltaE");
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, deltaE, 0);
|
||||
glViewport(0, 0, _deltaETableSize.x, _deltaETableSize.y);
|
||||
@@ -595,7 +595,7 @@ GLuint AtmosphereDeferredcaster::calculateDeltaE() {
|
||||
|
||||
std::pair<GLuint, GLuint> AtmosphereDeferredcaster::calculateDeltaS() {
|
||||
ZoneScoped
|
||||
|
||||
|
||||
GLuint deltaSRayleigh = createTexture(_textureSize, "DeltaS Rayleigh", 3);
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, deltaSRayleigh, 0);
|
||||
GLuint deltaSMie = createTexture(_textureSize, "DeltaS Mie", 3);
|
||||
@@ -649,7 +649,7 @@ std::pair<GLuint, GLuint> AtmosphereDeferredcaster::calculateDeltaS() {
|
||||
|
||||
void AtmosphereDeferredcaster::calculateIrradiance() {
|
||||
ZoneScoped
|
||||
|
||||
|
||||
glFramebufferTexture(
|
||||
GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
@@ -678,7 +678,7 @@ void AtmosphereDeferredcaster::calculateInscattering(GLuint deltaSRayleigh,
|
||||
GLuint deltaSMie)
|
||||
{
|
||||
ZoneScoped
|
||||
|
||||
|
||||
glFramebufferTexture(
|
||||
GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
@@ -726,7 +726,7 @@ void AtmosphereDeferredcaster::calculateDeltaJ(int scatteringOrder,
|
||||
GLuint deltaSRayleigh, GLuint deltaSMie)
|
||||
{
|
||||
ZoneScoped
|
||||
|
||||
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, deltaJ, 0);
|
||||
glViewport(0, 0, _textureSize.x, _textureSize.y);
|
||||
program.activate();
|
||||
@@ -745,7 +745,7 @@ void AtmosphereDeferredcaster::calculateDeltaJ(int scatteringOrder,
|
||||
deltaSRayleighUnit.activate();
|
||||
glBindTexture(GL_TEXTURE_3D, deltaSRayleigh);
|
||||
program.setUniform("deltaSRTexture", deltaSRayleighUnit);
|
||||
|
||||
|
||||
ghoul::opengl::TextureUnit deltaSMieUnit;
|
||||
deltaSMieUnit.activate();
|
||||
glBindTexture(GL_TEXTURE_3D, deltaSMie);
|
||||
@@ -784,7 +784,7 @@ void AtmosphereDeferredcaster::calculateDeltaE(int scatteringOrder,
|
||||
GLuint deltaSMie)
|
||||
{
|
||||
ZoneScoped
|
||||
|
||||
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, deltaE, 0);
|
||||
glViewport(0, 0, _deltaETableSize.x, _deltaETableSize.y);
|
||||
program.activate();
|
||||
@@ -823,7 +823,7 @@ void AtmosphereDeferredcaster::calculateDeltaS(int scatteringOrder,
|
||||
GLuint deltaSRayleigh, GLuint deltaJ)
|
||||
{
|
||||
ZoneScoped
|
||||
|
||||
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, deltaSRayleigh, 0);
|
||||
glViewport(0, 0, _textureSize.x, _textureSize.y);
|
||||
program.activate();
|
||||
@@ -863,7 +863,7 @@ void AtmosphereDeferredcaster::calculateIrradiance(int scatteringOrder,
|
||||
GLuint deltaE)
|
||||
{
|
||||
ZoneScoped
|
||||
|
||||
|
||||
glFramebufferTexture(
|
||||
GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
@@ -895,7 +895,7 @@ void AtmosphereDeferredcaster::calculateInscattering(int scatteringOrder,
|
||||
|
||||
{
|
||||
ZoneScoped
|
||||
|
||||
|
||||
glFramebufferTexture(
|
||||
GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
|
||||
@@ -114,9 +114,9 @@ private:
|
||||
|
||||
UniformCache(cullAtmosphere, Rg, Rt, groundRadianceEmission, HR, betaRayleigh, HM,
|
||||
betaMieExtinction, mieG, sunRadiance, ozoneLayerEnabled, HO, betaOzoneExtinction,
|
||||
SAMPLES_R, SAMPLES_MU, SAMPLES_MU_S, SAMPLES_NU, inverseModelTransformMatrix,
|
||||
SAMPLES_R, SAMPLES_MU, SAMPLES_MU_S, SAMPLES_NU, inverseModelTransformMatrix,
|
||||
modelTransformMatrix, projectionToModelTransform, viewToWorldMatrix,
|
||||
camPosObj, sunDirectionObj, hardShadows, transmittanceTexture, irradianceTexture,
|
||||
camPosObj, sunDirectionObj, hardShadows, transmittanceTexture, irradianceTexture,
|
||||
inscatterTexture) _uniformCache;
|
||||
|
||||
ghoul::opengl::TextureUnit _transmittanceTableTextureUnit;
|
||||
|
||||
@@ -649,8 +649,8 @@ void RenderableModel::render(const RenderData& data, RendererTasks&) {
|
||||
|
||||
// Model transform and view transform needs to be in double precision
|
||||
const glm::dmat4 modelTransform =
|
||||
glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * // Translation
|
||||
glm::dmat4(data.modelTransform.rotation) * // Spice rotation
|
||||
glm::translate(glm::dmat4(1.0), data.modelTransform.translation) *
|
||||
glm::dmat4(data.modelTransform.rotation) *
|
||||
glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)) *
|
||||
glm::scale(
|
||||
glm::dmat4(_modelTransform.value()),
|
||||
@@ -770,8 +770,9 @@ void RenderableModel::update(const UpdateData& data) {
|
||||
// be converted to the animation time range, so the animation knows which
|
||||
// keyframes it should interpolate between for each frame. The conversion is
|
||||
// done in different ways depending on the animation mode.
|
||||
// Explanation: s indicates start time, / indicates animation is played once forwards,
|
||||
// \ indicates animation is played once backwards, time moves to the right.
|
||||
// Explanation: s indicates start time, / indicates animation is played once
|
||||
// forwards, \ indicates animation is played once backwards, time moves to the
|
||||
// right.
|
||||
switch (_animationMode) {
|
||||
case AnimationMode::LoopFromStart:
|
||||
// Start looping from the start time
|
||||
|
||||
@@ -329,7 +329,12 @@ void RenderablePrism::render(const RenderData& data, RendererTasks&) {
|
||||
glLineWidth(_lineWidth);
|
||||
glBindVertexArray(_vaoId);
|
||||
|
||||
glDrawElements(GL_LINE_LOOP, static_cast<GLsizei>(_indexArray.size()), GL_UNSIGNED_BYTE, nullptr);
|
||||
glDrawElements(
|
||||
GL_LINE_LOOP,
|
||||
static_cast<GLsizei>(_indexArray.size()),
|
||||
GL_UNSIGNED_BYTE,
|
||||
nullptr
|
||||
);
|
||||
|
||||
glBindVertexArray(0);
|
||||
global::renderEngine->openglStateCache().resetLineState();
|
||||
|
||||
@@ -28,6 +28,13 @@
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/scene/translation.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/events/event.h>
|
||||
#include <openspace/events/eventengine.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
|
||||
@@ -151,7 +151,7 @@ int renderCameraPath(lua_State* L) {
|
||||
};
|
||||
|
||||
auto addDirectionLine = [addPoint, addLineBetweenPoints]
|
||||
(const std::string& pointId, const CameraPose& p,
|
||||
(const std::string& pointId, const CameraPose& p,
|
||||
double lineLength)
|
||||
{
|
||||
const glm::dvec3 dir = glm::normalize(p.rotation * glm::dvec3(0.0, 0.0, -1.0));
|
||||
@@ -291,7 +291,7 @@ int removePathControlPoints(lua_State* L) {
|
||||
int addCartesianAxes(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::addCartesianAxes");
|
||||
|
||||
auto [nodeIdentifier, scale] =
|
||||
auto [nodeIdentifier, scale] =
|
||||
ghoul::lua::values<std::string, std::optional<double>>(L);
|
||||
|
||||
SceneGraphNode* n = global::renderEngine->scene()->sceneGraphNode(nodeIdentifier);
|
||||
|
||||
@@ -557,7 +557,7 @@ void createExoplanetSystem(const std::string& starName) {
|
||||
|
||||
int addExoplanetSystem(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::addExoplanetSystem");
|
||||
std::variant<std::string, ghoul::Dictionary> v =
|
||||
std::variant<std::string, ghoul::Dictionary> v =
|
||||
ghoul::lua::value<std::variant<std::string, ghoul::Dictionary>>(L);
|
||||
|
||||
if (std::holds_alternative<std::string>(v)) {
|
||||
|
||||
@@ -462,7 +462,7 @@ void ConstructOctreeTask::constructOctreeFromFolder(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<float> filterValues;
|
||||
auto writeThreads = std::vector<std::thread>(8);
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ void ReadFitsTask::readAllFitsFilesFromFolder(const Task::ProgressCallback&) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t nInputFiles = allInputFiles.size();
|
||||
LINFO("Files to read: " + std::to_string(nInputFiles));
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace {
|
||||
struct [[codegen::Dictionary(ReadSpeckTask)]] Parameters {
|
||||
// The path to the SPECK file that are to be read
|
||||
std::string inFilePath;
|
||||
|
||||
|
||||
// The path to the file to export raw VBO data to
|
||||
std::string outFilePath;
|
||||
};
|
||||
|
||||
@@ -406,7 +406,7 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const {
|
||||
{
|
||||
// @TODO (2021-06-23, emmbr) Combine with the above function when the camera
|
||||
// paths work really well close to surfaces
|
||||
"flyToGeo",
|
||||
"flyToGeo",
|
||||
&globebrowsing::luascriptfunctions::flyToGeo,
|
||||
{},
|
||||
"[string], number, number, number [, bool, number]",
|
||||
|
||||
@@ -301,9 +301,8 @@ int flyToGeo(lua_State* L) {
|
||||
altitude
|
||||
);
|
||||
|
||||
using namespace std::string_literals;
|
||||
ghoul::Dictionary instruction;
|
||||
instruction.setValue("TargetType", "Node"s);
|
||||
instruction.setValue("TargetType", std::string("Node"));
|
||||
instruction.setValue("Target", n->identifier());
|
||||
instruction.setValue("Position", positionModelCoords);
|
||||
|
||||
|
||||
@@ -174,6 +174,15 @@ glm::vec3 GlobeRotation::computeSurfacePosition(double latitude, double longitud
|
||||
);
|
||||
}
|
||||
|
||||
void GlobeRotation::update(const UpdateData& data) {
|
||||
if (_useHeightmap) {
|
||||
// If we use the heightmap, we have to compute the height every frame
|
||||
setUpdateVariables();
|
||||
}
|
||||
|
||||
Rotation::update(data);
|
||||
}
|
||||
|
||||
glm::dmat3 GlobeRotation::matrix(const UpdateData&) const {
|
||||
if (!_globeNode) {
|
||||
// @TODO(abock): The const cast should be removed on a redesign of the rotation
|
||||
@@ -184,11 +193,6 @@ glm::dmat3 GlobeRotation::matrix(const UpdateData&) const {
|
||||
_matrixIsDirty = true;
|
||||
}
|
||||
|
||||
if (_useHeightmap) {
|
||||
// If we use the heightmap, we have to compute the height every frame
|
||||
_matrixIsDirty = true;
|
||||
}
|
||||
|
||||
if (!_matrixIsDirty) {
|
||||
return _matrix;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ class GlobeRotation : public Rotation {
|
||||
public:
|
||||
GlobeRotation(const ghoul::Dictionary& dictionary);
|
||||
|
||||
void update(const UpdateData& data) override;
|
||||
glm::dmat3 matrix(const UpdateData& data) const override;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
@@ -105,7 +105,7 @@ GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary)
|
||||
: _globe(GlobeInfo)
|
||||
, _latitude(LatitudeInfo, 0.0, -90.0, 90.0)
|
||||
, _longitude(LongitudeInfo, 0.0, -180.0, 180.0)
|
||||
, _altitude(AltitudeInfo, 0.0, 0.0, 1e12)
|
||||
, _altitude(AltitudeInfo, 0.0, -1e12, 1e12)
|
||||
, _useHeightmap(UseHeightmapInfo, false)
|
||||
{
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
@@ -121,7 +121,8 @@ GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary)
|
||||
addProperty(_longitude);
|
||||
|
||||
_altitude = p.altitude.value_or(_altitude);
|
||||
_altitude.setExponent(8.f);
|
||||
// @TODO (emmbr) uncomment when ranges with negative values are supported
|
||||
//_altitude.setExponent(8.f);
|
||||
_altitude.onChange([this]() { setUpdateVariables(); });
|
||||
addProperty(_altitude);
|
||||
|
||||
@@ -152,6 +153,15 @@ void GlobeTranslation::setUpdateVariables() {
|
||||
requireUpdate();
|
||||
}
|
||||
|
||||
void GlobeTranslation::update(const UpdateData& data) {
|
||||
if (_useHeightmap) {
|
||||
// If we use the heightmap, we have to compute the height every frame
|
||||
setUpdateVariables();
|
||||
}
|
||||
|
||||
Translation::update(data);
|
||||
}
|
||||
|
||||
glm::dvec3 GlobeTranslation::position(const UpdateData&) const {
|
||||
if (!_attachedNode) {
|
||||
// @TODO(abock): The const cast should be removed on a redesign of the translation
|
||||
@@ -162,11 +172,6 @@ glm::dvec3 GlobeTranslation::position(const UpdateData&) const {
|
||||
_positionIsDirty = true;
|
||||
}
|
||||
|
||||
if (_useHeightmap) {
|
||||
// If we use the heightmap, we have to compute the height every frame
|
||||
_positionIsDirty = true;
|
||||
}
|
||||
|
||||
if (!_positionIsDirty) {
|
||||
return _position;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ class GlobeTranslation : public Translation {
|
||||
public:
|
||||
GlobeTranslation(const ghoul::Dictionary& dictionary);
|
||||
|
||||
void update(const UpdateData& data) override;
|
||||
glm::dvec3 position(const UpdateData& data) const override;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
|
||||
#include <modules/globebrowsing/src/layer.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/events/event.h>
|
||||
#include <openspace/events/eventengine.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/profiling.h>
|
||||
|
||||
@@ -125,17 +128,18 @@ Layer* LayerGroup::addLayer(const ghoul::Dictionary& layerDict) {
|
||||
}
|
||||
|
||||
if (!layerDict.hasValue<std::string>("Identifier")) {
|
||||
LERROR("'Identifier' must be specified for layer.");
|
||||
LERROR("'Identifier' must be specified for layer");
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<Layer> layer = std::make_unique<Layer>(_groupId, layerDict, *this);
|
||||
layer->onChange(_onChangeCallback);
|
||||
if (hasPropertySubOwner(layer->identifier())) {
|
||||
LINFO("Layer with identifier " + layer->identifier() + " already exists.");
|
||||
std::string identifier = layerDict.value<std::string>("Identifier");
|
||||
if (hasPropertySubOwner(identifier)) {
|
||||
LINFO("Layer with identifier '" + identifier + "' already exists");
|
||||
_levelBlendingEnabled.setVisibility(properties::Property::Visibility::User);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<Layer> layer = std::make_unique<Layer>(_groupId, layerDict, *this);
|
||||
layer->onChange(_onChangeCallback);
|
||||
Layer* ptr = layer.get();
|
||||
_layers.push_back(std::move(layer));
|
||||
update();
|
||||
@@ -144,6 +148,17 @@ Layer* LayerGroup::addLayer(const ghoul::Dictionary& layerDict) {
|
||||
}
|
||||
addPropertySubOwner(ptr);
|
||||
_levelBlendingEnabled.setVisibility(properties::Property::Visibility::User);
|
||||
|
||||
properties::PropertyOwner* layerGroup = ptr->owner();
|
||||
properties::PropertyOwner* layerManager = layerGroup->owner();
|
||||
properties::PropertyOwner* globe = layerManager->owner();
|
||||
properties::PropertyOwner* sceneGraphNode = globe->owner();
|
||||
|
||||
global::eventEngine->publishEvent<events::EventLayerAdded>(
|
||||
sceneGraphNode->identifier(),
|
||||
layerGroup->identifier(),
|
||||
ptr->identifier()
|
||||
);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@@ -159,6 +174,15 @@ void LayerGroup::deleteLayer(const std::string& layerName) {
|
||||
removePropertySubOwner(it->get());
|
||||
(*it)->deinitialize();
|
||||
_layers.erase(it);
|
||||
properties::PropertyOwner* layerGroup = it->get()->owner();
|
||||
properties::PropertyOwner* layerManager = layerGroup->owner();
|
||||
properties::PropertyOwner* globe = layerManager->owner();
|
||||
properties::PropertyOwner* sceneGraphNode = globe->owner();
|
||||
global::eventEngine->publishEvent<events::EventLayerRemoved>(
|
||||
sceneGraphNode->identifier(),
|
||||
layerGroup->identifier(),
|
||||
it->get()->identifier()
|
||||
);
|
||||
update();
|
||||
if (_onChangeCallback) {
|
||||
_onChangeCallback(nullptr);
|
||||
|
||||
@@ -1209,8 +1209,8 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&,
|
||||
if (global::sessionRecording->isSavingFramesDuringPlayback()) {
|
||||
// If our tile cache is very full, we assume we need to adjust the level of detail
|
||||
// dynamically to not keep rendering frames with unavailable data
|
||||
// After certain number of iterations(_debugProperties.dynamicLodIterationCount) of
|
||||
// unavailable/available data in a row, we assume that a change could be made.
|
||||
// After certain number of iterations(_debugProperties.dynamicLodIterationCount)
|
||||
// of unavailable/available data in a row, we assume that a change could be made.
|
||||
const int iterCount = _debugProperties.dynamicLodIterationCount;
|
||||
const bool exceededIterations =
|
||||
static_cast<int>(_iterationsOfUnavailableData) > iterCount;
|
||||
|
||||
@@ -64,7 +64,8 @@ namespace {
|
||||
"modelViewProjectionMatrix", "textureOffset", "colorFilterValue", "nightFactor",
|
||||
"sunPosition", "sunPositionObj", "camPositionObj", "ringTextureFwrd",
|
||||
"ringTextureBckwrd", "ringTextureUnlit", "ringTextureColor",
|
||||
"ringTextureTransparency", "shadowMatrix", "shadowMapTexture", "zFightingPercentage"
|
||||
"ringTextureTransparency", "shadowMatrix", "shadowMapTexture",
|
||||
"zFightingPercentage"
|
||||
};
|
||||
|
||||
constexpr const std::array<const char*, 3> GeomUniformNames = {
|
||||
@@ -413,7 +414,10 @@ void RingsComponent::draw(const RenderData& data, RenderPass renderPass,
|
||||
modelViewProjectionTransform
|
||||
);
|
||||
_shader->setUniform(_uniformCacheAdvancedRings.textureOffset, _offset);
|
||||
_shader->setUniform(_uniformCacheAdvancedRings.colorFilterValue, _colorFilter);
|
||||
_shader->setUniform(
|
||||
_uniformCacheAdvancedRings.colorFilterValue,
|
||||
_colorFilter
|
||||
);
|
||||
_shader->setUniform(_uniformCacheAdvancedRings.nightFactor, _nightFactor);
|
||||
_shader->setUniform(_uniformCacheAdvancedRings.sunPosition, _sunPosition);
|
||||
|
||||
@@ -496,7 +500,10 @@ void RingsComponent::draw(const RenderData& data, RenderPass renderPass,
|
||||
ghoul::opengl::TextureUnit shadowMapUnit;
|
||||
shadowMapUnit.activate();
|
||||
glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture);
|
||||
_shader->setUniform(_uniformCacheAdvancedRings.shadowMapTexture, shadowMapUnit);
|
||||
_shader->setUniform(
|
||||
_uniformCacheAdvancedRings.shadowMapTexture,
|
||||
shadowMapUnit
|
||||
);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnablei(GL_BLEND, 0);
|
||||
|
||||
@@ -171,7 +171,7 @@ ShadowComponent::ShadowComponent(const ghoul::Dictionary& dictionary)
|
||||
return;
|
||||
}
|
||||
ghoul::Dictionary d = dictionary.value<ghoul::Dictionary>("Shadows");
|
||||
|
||||
|
||||
const Parameters p = codegen::bake<Parameters>(d);
|
||||
|
||||
addProperty(_enabled);
|
||||
|
||||
@@ -868,7 +868,7 @@ TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary)
|
||||
useFixedTime = dictionary.value<bool>(temporal::UseFixedTimeInfo.identifier);
|
||||
}
|
||||
addProperty(useFixedTime);
|
||||
|
||||
|
||||
if (dictionary.hasValue<std::string>(temporal::FixedTimeInfo.identifier)) {
|
||||
fixedTime = dictionary.value<std::string>(temporal::FixedTimeInfo.identifier);
|
||||
}
|
||||
@@ -891,7 +891,9 @@ bool initialize(TileProvider& tp) {
|
||||
|
||||
ghoul_assert(!tp.isInitialized, "TileProvider can only be initialized once.");
|
||||
|
||||
if (TileProvider::NumTileProviders > std::numeric_limits<uint16_t>::max() - 1) {
|
||||
if (TileProvider::NumTileProviders >
|
||||
static_cast<unsigned int>(std::numeric_limits<uint16_t>::max()) - 1)
|
||||
{
|
||||
LERRORC(
|
||||
"TileProvider",
|
||||
"Number of tile providers exceeds 65535. Something will break soon"
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_IMGUI___GUISHORTCUTSCOMPONENT___H__
|
||||
#define __OPENSPACE_MODULE_IMGUI___GUISHORTCUTSCOMPONENT___H__
|
||||
#ifndef __OPENSPACE_MODULE_IMGUI___GUIACTIONCOMPONENT___H__
|
||||
#define __OPENSPACE_MODULE_IMGUI___GUIACTIONCOMPONENT___H__
|
||||
|
||||
#include <modules/imgui/include/guicomponent.h>
|
||||
|
||||
@@ -38,4 +38,4 @@ public:
|
||||
|
||||
} // namespace openspace::gui
|
||||
|
||||
#endif // __OPENSPACE_MODULE_IMGUI___GUISHORTCUTSCOMPONENT___H__
|
||||
#endif // __OPENSPACE_MODULE_IMGUI___GUIACTIONCOMPONENT___H__
|
||||
|
||||
@@ -270,7 +270,10 @@ void renderStringProperty(Property* prop, const std::string& ownerName,
|
||||
void renderListProperty(const std::string& name, const std::string& fullIdentifier,
|
||||
const std::string& stringValue, IsRegularProperty isRegular)
|
||||
{
|
||||
ghoul_assert(stringValue.size() > 2, "an empty list should have the string value '[]'");
|
||||
ghoul_assert(
|
||||
stringValue.size() > 2,
|
||||
"an empty list should have the string value '[]'"
|
||||
);
|
||||
|
||||
// Remove brackets from the string value
|
||||
std::string value = stringValue.substr(1, stringValue.size() - 2);
|
||||
|
||||
@@ -529,35 +529,35 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary)
|
||||
_dataMapping.bvColor = p.dataMapping.bv.value_or("");
|
||||
_dataMapping.bvColor.onChange([this]() { _dataIsDirty = true; });
|
||||
_dataMappingContainer.addProperty(_dataMapping.bvColor);
|
||||
|
||||
|
||||
_dataMapping.luminance = p.dataMapping.luminance.value_or("");
|
||||
_dataMapping.luminance.onChange([this]() { _dataIsDirty = true; });
|
||||
_dataMappingContainer.addProperty(_dataMapping.luminance);
|
||||
|
||||
|
||||
_dataMapping.absoluteMagnitude = p.dataMapping.absoluteMagnitude.value_or("");
|
||||
_dataMapping.absoluteMagnitude.onChange([this]() { _dataIsDirty = true; });
|
||||
_dataMappingContainer.addProperty(_dataMapping.absoluteMagnitude);
|
||||
|
||||
|
||||
_dataMapping.apparentMagnitude = p.dataMapping.apparentMagnitude.value_or("");
|
||||
_dataMapping.apparentMagnitude.onChange([this]() { _dataIsDirty = true; });
|
||||
_dataMappingContainer.addProperty(_dataMapping.apparentMagnitude);
|
||||
|
||||
|
||||
_dataMapping.vx = p.dataMapping.vx.value_or("");
|
||||
_dataMapping.vx.onChange([this]() { _dataIsDirty = true; });
|
||||
_dataMappingContainer.addProperty(_dataMapping.vx);
|
||||
|
||||
|
||||
_dataMapping.vy = p.dataMapping.vy.value_or("");
|
||||
_dataMapping.vy.onChange([this]() { _dataIsDirty = true; });
|
||||
_dataMappingContainer.addProperty(_dataMapping.vy);
|
||||
|
||||
|
||||
_dataMapping.vz = p.dataMapping.vz.value_or("");
|
||||
_dataMapping.vz.onChange([this]() { _dataIsDirty = true; });
|
||||
_dataMappingContainer.addProperty(_dataMapping.vz);
|
||||
|
||||
|
||||
_dataMapping.speed = p.dataMapping.speed.value_or("");
|
||||
_dataMapping.speed.onChange([this]() { _dataIsDirty = true; });
|
||||
_dataMappingContainer.addProperty(_dataMapping.speed);
|
||||
|
||||
|
||||
addPropertySubOwner(_dataMappingContainer);
|
||||
|
||||
_speckFile = p.speckFile.string();
|
||||
|
||||
@@ -172,7 +172,7 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines)
|
||||
if (startsWith(line, "datavar")) {
|
||||
// each datavar line is following the form:
|
||||
// datavar <idx> <description>
|
||||
// with <idx> being the index of the data variable
|
||||
// with <idx> being the index of the data variable
|
||||
|
||||
std::stringstream str(line);
|
||||
std::string dummy;
|
||||
@@ -197,7 +197,7 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines)
|
||||
std::stringstream str(line);
|
||||
std::string dummy;
|
||||
str >> dummy >> res.textureDataIndex;
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -216,8 +216,8 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines)
|
||||
std::stringstream str(line);
|
||||
std::string dummy;
|
||||
str >> dummy >> res.orientationDataIndex;
|
||||
|
||||
// Ok.. this is kind of weird. Speck unfortunately doesn't tell us in the
|
||||
|
||||
// Ok.. this is kind of weird. Speck unfortunately doesn't tell us in the
|
||||
// specification how many values a datavar has. Usually this is 1 value per
|
||||
// datavar, unless it is a polygon orientation thing. Now, the datavar name
|
||||
// for these can be anything (have seen 'orientation' and 'ori' before, so we
|
||||
@@ -268,7 +268,7 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines)
|
||||
return lhs.index < rhs.index;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
std::sort(
|
||||
res.textures.begin(), res.textures.end(),
|
||||
[](const Dataset::Texture& lhs, const Dataset::Texture& rhs) {
|
||||
@@ -292,7 +292,7 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines)
|
||||
if (line.back() == '\r') {
|
||||
line = line.substr(0, line.length() - 1);
|
||||
}
|
||||
|
||||
|
||||
strip(line);
|
||||
|
||||
if (line.empty()) {
|
||||
@@ -357,7 +357,7 @@ std::optional<Dataset> loadCachedFile(std::filesystem::path path) {
|
||||
if (!file.good()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
Dataset result;
|
||||
|
||||
int8_t fileVersion;
|
||||
@@ -394,7 +394,7 @@ std::optional<Dataset> loadCachedFile(std::filesystem::path path) {
|
||||
result.textures.resize(nTextures);
|
||||
for (int i = 0; i < nTextures; i += 1) {
|
||||
Dataset::Texture tex;
|
||||
|
||||
|
||||
int16_t idx;
|
||||
file.read(reinterpret_cast<char*>(&idx), sizeof(int16_t));
|
||||
tex.index = idx;
|
||||
@@ -784,7 +784,7 @@ ColorMap loadFile(std::filesystem::path path, SkipAllZeroLines) {
|
||||
if (nColorLines == -1) {
|
||||
// This is the first time we get this far, it will have to be the first number
|
||||
// meaning that it is the number of color values
|
||||
|
||||
|
||||
str >> nColorLines;
|
||||
res.entries.reserve(nColorLines);
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ RenderableFov::RenderableFov(const ghoul::Dictionary& dictionary)
|
||||
|
||||
_alwaysDrawFov = p.alwaysDrawFov.value_or(_alwaysDrawFov);
|
||||
addProperty(_alwaysDrawFov);
|
||||
|
||||
|
||||
_simplifyBounds = p.simplifyBounds.value_or(_simplifyBounds);
|
||||
|
||||
addProperty(_colors.defaultStart);
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace {
|
||||
};
|
||||
|
||||
constexpr const std::array<const char*, 6> FboUniformNames = {
|
||||
"projectionTexture", "ProjectorMatrix", "ModelTransform",
|
||||
"projectionTexture", "ProjectorMatrix", "ModelTransform",
|
||||
"boresight", "radius", "segments"
|
||||
};
|
||||
|
||||
|
||||
@@ -42,9 +42,9 @@ class SequenceParser;
|
||||
* large image data-sets across all openspace renderable instances, both for past and
|
||||
* future unmanned-spacecraft missions. To load the instance with data the client must
|
||||
* provide a parser inherited from the abstract base class SequenceParser. Hence, there is
|
||||
* no restriction imposed on data input, whether its data in the form of existing images or
|
||||
* in the form of a planned observation schedule. Notably, in order for the sequencer to
|
||||
* function the client must provide or write a parser that fills the ImageSequencers
|
||||
* no restriction imposed on data input, whether its data in the form of existing images
|
||||
* or in the form of a planned observation schedule. Notably, in order for the sequencer
|
||||
* to function the client must provide or write a parser that fills the ImageSequencers
|
||||
* private members.
|
||||
*
|
||||
* \see SequenceParser
|
||||
@@ -136,7 +136,7 @@ private:
|
||||
void sortData();
|
||||
|
||||
/**
|
||||
* This handles any types of ambiguities between the data and SPICE calls. This map is
|
||||
* This handles any types of ambiguities between the data and SPICE calls. This map is
|
||||
* composed of a key that is a string in the data to be translated and a Decoder that
|
||||
* holds the corresponding translation provided through as asset.
|
||||
* \see Decoder
|
||||
@@ -179,7 +179,7 @@ private:
|
||||
std::string _defaultCaptureImage;
|
||||
|
||||
std::map<std::string, Image> _latestImages;
|
||||
|
||||
|
||||
// if no data, no run
|
||||
bool _hasData = false;
|
||||
};
|
||||
|
||||
@@ -109,8 +109,8 @@ namespace {
|
||||
InstrumentTimes [[codegen::key("instrument-times")]],
|
||||
ImageAndInstrumentTimes [[codegen::key("image-and-instrument-times")]]
|
||||
};
|
||||
// This value determines which type of sequencer is used for generating image
|
||||
// schedules. The 'playbook' is using a custom format designed by the New Horizons
|
||||
// This value determines which type of sequencer is used for generating image
|
||||
// schedules. The 'playbook' is using a custom format designed by the New Horizons
|
||||
// team, the 'image-sequence' uses lbl files from a directory, and the 'hybrid'
|
||||
// uses both methods
|
||||
std::optional<Type> sequenceType;
|
||||
@@ -128,7 +128,7 @@ namespace {
|
||||
// SPICE integer
|
||||
std::string target [[codegen::annotation("A SPICE name of the observed object")]];
|
||||
|
||||
// The aberration correction that is supposed to be used for the projection. The
|
||||
// The aberration correction that is supposed to be used for the projection. The
|
||||
// values for the correction correspond to the SPICE definition as described in
|
||||
// ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/IDL/cspice/spkezr_c.html
|
||||
std::string aberration [[codegen::inlist("NONE", "LT", "LT+S", "CN", "CN+S",
|
||||
@@ -137,18 +137,18 @@ namespace {
|
||||
// The list of potential targets that are involved with the image projection
|
||||
std::optional<std::vector<std::string>> potentialTargets;
|
||||
|
||||
// Determines whether the object requires a self-shadowing algorithm. This is
|
||||
// necessary if the object is concave and might cast a shadow on itself during
|
||||
// Determines whether the object requires a self-shadowing algorithm. This is
|
||||
// necessary if the object is concave and might cast a shadow on itself during
|
||||
// presentation. The default value is 'false'
|
||||
std::optional<bool> textureMap;
|
||||
|
||||
// Determines whether the object requires a self-shadowing algorithm. This is
|
||||
// necessary if the object is concave and might cast a shadow on itself during
|
||||
// Determines whether the object requires a self-shadowing algorithm. This is
|
||||
// necessary if the object is concave and might cast a shadow on itself during
|
||||
// presentation. The default value is 'false'
|
||||
std::optional<bool> shadowMap;
|
||||
|
||||
// Sets the desired aspect ratio of the projected texture. This might be necessary
|
||||
// as planets usually have 2x1 aspect ratios, whereas this does not hold for
|
||||
// Sets the desired aspect ratio of the projected texture. This might be necessary
|
||||
// as planets usually have 2x1 aspect ratios, whereas this does not hold for
|
||||
// non-planet objects (comets, asteroids, etc). The default value is '1.0'
|
||||
std::optional<float> aspectRatio;
|
||||
|
||||
|
||||
@@ -194,7 +194,8 @@ scripting::LuaLibrary StateMachineModule::luaLibrary() const {
|
||||
&luascriptfunctions::printCurrentStateInfo,
|
||||
{},
|
||||
"",
|
||||
"Prints information about the current state and possible transitions to the log."
|
||||
"Prints information about the current state and possible transitions to the "
|
||||
"log."
|
||||
},
|
||||
{
|
||||
"saveToDotFile",
|
||||
|
||||
@@ -49,22 +49,22 @@ namespace {
|
||||
// provided, all files will be downloaded to the same directory
|
||||
std::variant<std::string, std::vector<std::string>> url;
|
||||
|
||||
// This optional identifier will be part of the used folder structure and, if
|
||||
// This optional identifier will be part of the used folder structure and, if
|
||||
// provided, can be used to manually find the downloaded folder in the
|
||||
// synchronization folder. If this value is not specified, 'UseHash' has to be set
|
||||
// to 'true'
|
||||
std::optional<std::string> identifier;
|
||||
|
||||
// If this value is set to 'true' and it is not overwritten by the global
|
||||
// settings, the file(s) pointed to by this URLSynchronization will always be
|
||||
// downloaded, thus overwriting the local files. This is useful for files that are
|
||||
// settings, the file(s) pointed to by this URLSynchronization will always be
|
||||
// downloaded, thus overwriting the local files. This is useful for files that are
|
||||
// updated regularly remotely and should be fetch at every startup
|
||||
std::optional<bool> forceOverride [[codegen::key("override")]];
|
||||
|
||||
// If this value is set to 'true' (the default), the hash of the URL is appended
|
||||
// to the directory name to produce a unique directory under all circumstances. If
|
||||
// to the directory name to produce a unique directory under all circumstances. If
|
||||
// this is not desired, the URLSynchronization use the bare directory name alone
|
||||
// if this value is 'false'. If this value is 'false', the identifier has to be
|
||||
// if this value is 'false'. If this value is 'false', the identifier has to be
|
||||
// specified
|
||||
std::optional<bool> useHash;
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq,
|
||||
void (*grad)(double *, double *, int, void *, LMstat*),
|
||||
void *fdata, LMstat *lmstat) {
|
||||
|
||||
int x, i, j, it, nit, ill;
|
||||
int x, j, it, nit, ill;
|
||||
bool verbose;
|
||||
std::string data;
|
||||
double lambda, up, down, mult, weight, err, newerr, derr, target_derr;
|
||||
@@ -86,7 +86,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq,
|
||||
|
||||
defer {
|
||||
// deallocate the arrays
|
||||
for (i = 0; i < npar; i++) {
|
||||
for (int i = 0; i < npar; i++) {
|
||||
delete[] h[i];
|
||||
delete[] ch[i];
|
||||
}
|
||||
@@ -109,7 +109,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq,
|
||||
|
||||
if (verbose) {
|
||||
std::ostringstream qs, gs, ds, ps, oss;
|
||||
for (i = 0; i < npar; ++i) {
|
||||
for (int i = 0; i < npar; ++i) {
|
||||
qs << "q" << i;
|
||||
gs << "g" << i;
|
||||
ds << "d" << i;
|
||||
@@ -119,7 +119,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq,
|
||||
ds << ",";
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ny; ++i) {
|
||||
for (int i = 0; i < ny; ++i) {
|
||||
for (j = 0; j < 2; ++j) {
|
||||
std::string s = (j == 0) ? "x" : "y";
|
||||
ps << "p" << i << s;
|
||||
@@ -153,7 +153,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq,
|
||||
}
|
||||
|
||||
// calculate the approximation to the Hessian and the "derivative" d
|
||||
for (i = 0; i < npar; i++) {
|
||||
for (int i = 0; i < npar; i++) {
|
||||
d[i] = 0;
|
||||
for (j = 0; j <= i; j++) {
|
||||
h[i][j] = 0;
|
||||
@@ -164,7 +164,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq,
|
||||
weight = 1 / dysq[x]; // for weighted least-squares
|
||||
}
|
||||
grad(g, par, x, fdata, lmstat);
|
||||
for (i = 0; i < npar; i++) {
|
||||
for (int i = 0; i < npar; i++) {
|
||||
d[i] += (0.0 - func(par, x, fdata, lmstat)) * g[i] * weight; //(y[x] - func(par, x, fdata)) * g[i] * weight;
|
||||
for (j = 0; j <= i; j++) {
|
||||
h[i][j] += g[i] * g[j] * weight;
|
||||
@@ -175,13 +175,13 @@ bool levmarq(int npar, double *par, int ny, double *dysq,
|
||||
mult = 1 + lambda;
|
||||
ill = 1; // ill-conditioned?
|
||||
while (ill && (it < nit)) {
|
||||
for (i = 0; i < npar; i++) {
|
||||
for (int i = 0; i < npar; i++) {
|
||||
h[i][i] = h[i][i] * mult;
|
||||
}
|
||||
ill = cholesky_decomp(npar, ch, h);
|
||||
if (!ill) {
|
||||
solve_axb_cholesky(npar, ch, delta, d);
|
||||
for (i = 0; i < npar; i++) {
|
||||
for (int i = 0; i < npar; i++) {
|
||||
newpar[i] = par[i] + delta[i];
|
||||
}
|
||||
lmstat->pos.clear();
|
||||
@@ -197,7 +197,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq,
|
||||
printf("\n");*/
|
||||
|
||||
std::ostringstream gString, qString, dString, pString, os;
|
||||
for (i = 0; i < npar; ++i) {
|
||||
for (int i = 0; i < npar; ++i) {
|
||||
gString << g[i];
|
||||
qString << par[i];
|
||||
dString << d[i];
|
||||
@@ -207,7 +207,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq,
|
||||
dString << ",";
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ny; ++i) {
|
||||
for (int i = 0; i < ny; ++i) {
|
||||
pString << lmstat->pos.at(i).x << "," << lmstat->pos.at(i).y;
|
||||
if (i + 1 < ny) {
|
||||
pString << ",";
|
||||
@@ -222,7 +222,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq,
|
||||
it++;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < npar; i++) {
|
||||
for (int i = 0; i < npar; i++) {
|
||||
par[i] = newpar[i];
|
||||
}
|
||||
err = newerr;
|
||||
|
||||
@@ -93,7 +93,7 @@ std::string GenerateRawVolumeTask::description() {
|
||||
"value by evaluating the lua function: `{}`, with three arguments (x, y, z) "
|
||||
"ranging from ({}, {}, {}) to ({}, {}, {}). Write raw volume data into {} and "
|
||||
"dictionary with metadata to {}",
|
||||
_dimensions.x, _dimensions.y, _dimensions.z, _valueFunctionLua,
|
||||
_dimensions.x, _dimensions.y, _dimensions.z, _valueFunctionLua,
|
||||
_lowerDomainBound.x, _lowerDomainBound.y, _lowerDomainBound.z,
|
||||
_upperDomainBound.x, _upperDomainBound.y, _upperDomainBound.z,
|
||||
_rawVolumeOutputPath, _dictionaryOutputPath
|
||||
|
||||
@@ -222,6 +222,7 @@ LoadingScreen = {
|
||||
}
|
||||
CheckOpenGLState = false
|
||||
LogEachOpenGLCall = false
|
||||
PrintEvents = false
|
||||
|
||||
ShutdownCountdown = 3
|
||||
ScreenshotUseDate = true
|
||||
|
||||
@@ -43,6 +43,9 @@ set(OPENSPACE_SOURCE
|
||||
${OPENSPACE_BASE_DIR}/src/engine/openspaceengine_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/engine/syncengine.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/engine/virtualpropertymanager.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/events/event.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/events/eventengine.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/events/eventengine_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/actionmanager.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/actionmanager_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/camerainteractionstates.cpp
|
||||
@@ -176,6 +179,7 @@ set(OPENSPACE_SOURCE
|
||||
${OPENSPACE_BASE_DIR}/src/util/spicemanager_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/util/syncbuffer.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/util/synchronizationwatcher.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/util/tstring.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/util/histogram.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/util/task.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/util/taskloader.cpp
|
||||
@@ -223,6 +227,9 @@ set(OPENSPACE_HEADER
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/engine/syncengine.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/engine/virtualpropertymanager.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/engine/windowdelegate.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/events/event.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/events/eventengine.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/events/eventengine.inl
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/action.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/actionmanager.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.h
|
||||
@@ -381,6 +388,7 @@ set(OPENSPACE_HEADER
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/util/timemanager.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/util/timerange.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/util/touch.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/util/tstring.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/util/universalhelpers.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/util/updatestructures.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/util/versionchecker.h
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <openspace/engine/logfactory.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/events/eventengine.h>
|
||||
#include <openspace/interaction/actionmanager.h>
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
#include <openspace/interaction/sessionrecording.h>
|
||||
@@ -77,13 +78,14 @@ void registerCoreClasses(documentation::DocumentationEngine& engine) {
|
||||
// documentation version.
|
||||
void registerCoreClasses(scripting::ScriptEngine& engine) {
|
||||
engine.addLibrary(Dashboard::luaLibrary());
|
||||
engine.addLibrary(EventEngine::luaLibrary());
|
||||
engine.addLibrary(MissionManager::luaLibrary());
|
||||
engine.addLibrary(ModuleEngine::luaLibrary());
|
||||
engine.addLibrary(OpenSpaceEngine::luaLibrary());
|
||||
engine.addLibrary(ParallelPeer::luaLibrary());
|
||||
engine.addLibrary(Profile::luaLibrary());
|
||||
engine.addLibrary(RenderEngine::luaLibrary());
|
||||
engine.addLibrary(SpiceManager::luaLibrary());
|
||||
engine.addLibrary(Profile::luaLibrary());
|
||||
engine.addLibrary(Scene::luaLibrary());
|
||||
engine.addLibrary(Time::luaLibrary());
|
||||
engine.addLibrary(interaction::ActionManager::luaLibrary());
|
||||
|
||||
@@ -462,7 +462,7 @@ TestResult TemplateVerifier<glm::ivec2>::operator()(const ghoul::Dictionary& dic
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::MissingKey;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -498,7 +498,7 @@ TestResult TemplateVerifier<glm::ivec3>::operator()(const ghoul::Dictionary& dic
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -508,7 +508,7 @@ TestResult TemplateVerifier<glm::ivec3>::operator()(const ghoul::Dictionary& dic
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -565,7 +565,7 @@ TestResult TemplateVerifier<glm::ivec4>::operator()(const ghoul::Dictionary& dic
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -575,7 +575,7 @@ TestResult TemplateVerifier<glm::ivec4>::operator()(const ghoul::Dictionary& dic
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::MissingKey;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,6 +295,11 @@ namespace {
|
||||
// 'false'
|
||||
std::optional<bool> logEachOpenGLCall;
|
||||
|
||||
// Determines whether events are printed as debug messages to the console each
|
||||
// frame. If this value is set it determines the default value of the property of
|
||||
// the OpenSpaceEngine with the same name
|
||||
std::optional<bool> printEvents;
|
||||
|
||||
// This value determines whether the initialization of the scene graph should
|
||||
// occur multithreaded, that is, whether multiple scene graph nodes should
|
||||
// initialize in parallel. The only use for this value is to disable it for
|
||||
@@ -391,6 +396,7 @@ void parseLuaState(Configuration& configuration) {
|
||||
p.useMultithreadedInitialization.value_or(c.useMultithreadedInitialization);
|
||||
c.isCheckingOpenGLState = p.checkOpenGLState.value_or(c.isCheckingOpenGLState);
|
||||
c.isLoggingOpenGLCalls = p.logEachOpenGLCall.value_or(c.isLoggingOpenGLCalls);
|
||||
c.isPrintingEvents = p.printEvents.value_or(c.isPrintingEvents);
|
||||
c.shutdownCountdown = p.shutdownCountdown.value_or(c.shutdownCountdown);
|
||||
c.shouldUseScreenshotDate = p.screenshotUseDate.value_or(c.shouldUseScreenshotDate);
|
||||
if (p.onScreenTextScaling.has_value()) {
|
||||
|
||||
@@ -173,9 +173,10 @@ std::shared_ptr<DownloadManager::FileFuture> DownloadManager::downloadFile(
|
||||
CURL* curl = curl_easy_init();
|
||||
if (curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // NOLINT
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "OpenSpace"); // NOLINT
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // NOLINT
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); // NOLINT
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData); // NOLINT
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeData); // NOLINT
|
||||
if (timeout_secs) {
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout_secs); // NOLINT
|
||||
}
|
||||
@@ -204,7 +205,11 @@ std::shared_ptr<DownloadManager::FileFuture> DownloadManager::downloadFile(
|
||||
future->isFinished = true;
|
||||
}
|
||||
else {
|
||||
future->errorMessage = curl_easy_strerror(res);
|
||||
long rescode;
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &rescode);
|
||||
future->errorMessage = fmt::format(
|
||||
"{}. HTTP code: {}", curl_easy_strerror(res), rescode
|
||||
);
|
||||
}
|
||||
|
||||
if (finishedCb) {
|
||||
|
||||
+34
-17
@@ -24,14 +24,15 @@
|
||||
|
||||
#include <openspace/engine/globals.h>
|
||||
|
||||
#include <openspace/engine/downloadmanager.h>
|
||||
#include <openspace/engine/configuration.h>
|
||||
#include <openspace/engine/downloadmanager.h>
|
||||
#include <openspace/engine/globalscallbacks.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/engine/syncengine.h>
|
||||
#include <openspace/engine/virtualpropertymanager.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/events/eventengine.h>
|
||||
#include <openspace/interaction/actionmanager.h>
|
||||
#include <openspace/interaction/interactionmonitor.h>
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
@@ -71,12 +72,13 @@ namespace {
|
||||
// in some random global randoms
|
||||
#ifdef WIN32
|
||||
constexpr const int TotalSize =
|
||||
sizeof(MemoryManager) +
|
||||
sizeof(EventEngine) +
|
||||
sizeof(ghoul::fontrendering::FontManager) +
|
||||
sizeof(Dashboard) +
|
||||
sizeof(DeferredcasterManager) +
|
||||
sizeof(DownloadManager) +
|
||||
sizeof(LuaConsole) +
|
||||
sizeof(MemoryManager) +
|
||||
sizeof(MissionManager) +
|
||||
sizeof(ModuleEngine) +
|
||||
sizeof(OpenSpaceEngine) +
|
||||
@@ -119,6 +121,22 @@ void create() {
|
||||
std::byte* currentPos = DataStorage.data();
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef WIN32
|
||||
memoryManager = new (currentPos) MemoryManager;
|
||||
ghoul_assert(memoryManager, "No memoryManager");
|
||||
currentPos += sizeof(MemoryManager);
|
||||
#else // ^^^ WIN32 / !WIN32 vvv
|
||||
memoryManager = new MemoryManager;
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef WIN32
|
||||
eventEngine = new (currentPos) EventEngine;
|
||||
ghoul_assert(eventEngine, "No eventEngine");
|
||||
currentPos += sizeof(EventEngine);
|
||||
#else // ^^^ WIN32 / !WIN32 vvv
|
||||
downloadManager = new EventEngine;
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef WIN32
|
||||
fontManager = new (currentPos) ghoul::fontrendering::FontManager({ 1536, 1536, 1 });
|
||||
ghoul_assert(fontManager, "No fontManager");
|
||||
@@ -159,14 +177,6 @@ void create() {
|
||||
luaConsole = new LuaConsole;
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef WIN32
|
||||
memoryManager = new (currentPos) MemoryManager;
|
||||
ghoul_assert(memoryManager, "No memoryManager");
|
||||
currentPos += sizeof(MemoryManager);
|
||||
#else // ^^^ WIN32 / !WIN32 vvv
|
||||
memoryManager = new MemoryManager;
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef WIN32
|
||||
missionManager = new (currentPos) MissionManager;
|
||||
ghoul_assert(missionManager, "No missionManager");
|
||||
@@ -573,13 +583,6 @@ void destroy() {
|
||||
delete missionManager;
|
||||
#endif // WIN32
|
||||
|
||||
LDEBUGC("Globals", "Destroying 'MemoryManager'");
|
||||
#ifdef WIN32
|
||||
memoryManager->~MemoryManager();
|
||||
#else // ^^^ WIN32 / !WIN32 vvv
|
||||
delete memoryManager;
|
||||
#endif // WIN32
|
||||
|
||||
LDEBUGC("Globals", "Destroying 'LuaConsole'");
|
||||
#ifdef WIN32
|
||||
luaConsole->~LuaConsole();
|
||||
@@ -615,6 +618,20 @@ void destroy() {
|
||||
delete fontManager;
|
||||
#endif // WIN32
|
||||
|
||||
LDEBUGC("Globals", "Destroying 'EventEngine'");
|
||||
#ifdef WIN32
|
||||
eventEngine->~EventEngine();
|
||||
#else // ^^^ WIN32 / !WIN32 vvv
|
||||
delete eventEngine;
|
||||
#endif // WIN32
|
||||
|
||||
LDEBUGC("Globals", "Destroying 'MemoryManager'");
|
||||
#ifdef WIN32
|
||||
memoryManager->~MemoryManager();
|
||||
#else // ^^^ WIN32 / !WIN32 vvv
|
||||
delete memoryManager;
|
||||
#endif // WIN32
|
||||
|
||||
callback::destroy();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#include <openspace/engine/syncengine.h>
|
||||
#include <openspace/engine/virtualpropertymanager.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/events/event.h>
|
||||
#include <openspace/events/eventengine.h>
|
||||
#include <openspace/interaction/actionmanager.h>
|
||||
#include <openspace/interaction/interactionmonitor.h>
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
@@ -53,6 +55,7 @@
|
||||
#include <openspace/scene/assetloader.h>
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/scene/rotation.h>
|
||||
#include <openspace/scene/scale.h>
|
||||
#include <openspace/scene/timeframe.h>
|
||||
@@ -101,13 +104,22 @@ namespace {
|
||||
template <class... Ts> overloaded(Ts...)->overloaded<Ts...>;
|
||||
|
||||
constexpr const char* _loggerCat = "OpenSpaceEngine";
|
||||
|
||||
openspace::properties::Property::PropertyInfo PrintEventsInfo = {
|
||||
"PrintEvents",
|
||||
"Print Events",
|
||||
"If this is enabled, all events that are propagated through the system are "
|
||||
"printed to the log."
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class Scene;
|
||||
|
||||
OpenSpaceEngine::OpenSpaceEngine() {
|
||||
OpenSpaceEngine::OpenSpaceEngine()
|
||||
: _printEvents(PrintEventsInfo, false)
|
||||
{
|
||||
FactoryManager::initialize();
|
||||
FactoryManager::ref().addFactory(
|
||||
std::make_unique<ghoul::TemplateFactory<Renderable>>(),
|
||||
@@ -186,6 +198,8 @@ void OpenSpaceEngine::initialize() {
|
||||
|
||||
global::initialize();
|
||||
|
||||
_printEvents = global::configuration->isPrintingEvents;
|
||||
|
||||
const std::string versionCheckUrl = global::configuration->versionCheckUrl;
|
||||
if (!versionCheckUrl.empty()) {
|
||||
global::versionChecker->requestLatestVersion(versionCheckUrl);
|
||||
@@ -895,13 +909,16 @@ void OpenSpaceEngine::deinitialize() {
|
||||
TransformationManager::deinitialize();
|
||||
SpiceManager::deinitialize();
|
||||
|
||||
if (_printEvents) {
|
||||
events::Event* e = global::eventEngine->firstEvent();
|
||||
events::logAllEvents(e);
|
||||
}
|
||||
|
||||
ghoul::fontrendering::FontRenderer::deinitialize();
|
||||
|
||||
ghoul::logging::LogManager::deinitialize();
|
||||
|
||||
LTRACE("deinitialize(end)");
|
||||
|
||||
|
||||
LTRACE("OpenSpaceEngine::deinitialize(end)");
|
||||
}
|
||||
|
||||
@@ -1101,6 +1118,7 @@ void OpenSpaceEngine::preSynchronization() {
|
||||
resetPropertyChangeFlagsOfSubowners(global::rootPropertyOwner);
|
||||
_hasScheduledAssetLoading = false;
|
||||
_scheduledAssetPathToLoad.clear();
|
||||
global::eventEngine->publishEvent<events::EventProfileLoadingFinished>();
|
||||
}
|
||||
else if (_isRenderingFirstFrame) {
|
||||
global::profile->ignoreUpdates = true;
|
||||
@@ -1186,6 +1204,9 @@ void OpenSpaceEngine::postSynchronizationPreDraw() {
|
||||
|
||||
if (_shutdown.inShutdown) {
|
||||
if (_shutdown.timer <= 0.f) {
|
||||
global::eventEngine->publishEvent<events::EventApplicationShutdown>(
|
||||
events::EventApplicationShutdown::State::Finished
|
||||
);
|
||||
global::windowDelegate->terminate();
|
||||
return;
|
||||
}
|
||||
@@ -1311,6 +1332,23 @@ void OpenSpaceEngine::postDraw() {
|
||||
_isRenderingFirstFrame = false;
|
||||
}
|
||||
|
||||
//
|
||||
// Handle events
|
||||
//
|
||||
const events::Event* e = global::eventEngine->firstEvent();
|
||||
if (_printEvents) {
|
||||
events::logAllEvents(e);
|
||||
}
|
||||
global::eventEngine->triggerActions();
|
||||
while (e) {
|
||||
// @TODO (abock, 2021-08-25) Need to send all events to a topic to be sent out to
|
||||
// others
|
||||
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
|
||||
global::eventEngine->postFrameCleanup();
|
||||
global::memoryManager->PersistentMemory.housekeeping();
|
||||
|
||||
LTRACE("OpenSpaceEngine::postDraw(end)");
|
||||
@@ -1544,15 +1582,24 @@ void OpenSpaceEngine::toggleShutdownMode() {
|
||||
if (_shutdown.inShutdown) {
|
||||
// If we are already in shutdown mode, we want to disable it
|
||||
_shutdown.inShutdown = false;
|
||||
global::eventEngine->publishEvent<events::EventApplicationShutdown>(
|
||||
events::EventApplicationShutdown::State::Aborted
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Else, we have to enable it
|
||||
_shutdown.timer = _shutdown.waitTime;
|
||||
_shutdown.inShutdown = true;
|
||||
global::eventEngine->publishEvent<events::EventApplicationShutdown>(
|
||||
events::EventApplicationShutdown::State::Started
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void setCameraFromProfile(const Profile& p) {
|
||||
if (!p.camera.has_value()) {
|
||||
throw ghoul::RuntimeError("No 'camera' entry exists in the startup profile");
|
||||
}
|
||||
std::visit(
|
||||
overloaded{
|
||||
[](const Profile::CameraNavState& navStateProfile) {
|
||||
|
||||
@@ -0,0 +1,595 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* 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/events/event.h>
|
||||
|
||||
#include <openspace/properties/property.h>
|
||||
#include <openspace/rendering/screenspacerenderable.h>
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/util/time.h>
|
||||
#include <openspace/util/tstring.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <functional>
|
||||
|
||||
namespace {
|
||||
constexpr const char _loggerCat[] = "EventInfo";
|
||||
} // namespace
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
namespace openspace::events {
|
||||
|
||||
void log(int i, const EventSceneGraphNodeAdded& e) {
|
||||
ghoul_assert(e.type == EventSceneGraphNodeAdded::Type, "Wrong type");
|
||||
LINFO(fmt::format("[{}] SceneGraphNodeAdded: {}", i, e.node));
|
||||
}
|
||||
|
||||
void log(int i, const EventSceneGraphNodeRemoved& e) {
|
||||
ghoul_assert(e.type == EventSceneGraphNodeRemoved::Type, "Wrong type");
|
||||
LINFO(fmt::format("[{}] SceneGraphNodeRemoved: {}", i, e.node));
|
||||
}
|
||||
|
||||
void log(int i, const EventParallelConnection& e) {
|
||||
ghoul_assert(e.type == EventParallelConnection::Type, "Wrong type");
|
||||
std::string_view state = [](EventParallelConnection::State s) {
|
||||
switch (s) {
|
||||
case EventParallelConnection::State::Established: return "Established";
|
||||
case EventParallelConnection::State::Lost: return "Lost";
|
||||
case EventParallelConnection::State::HostshipGained: return "HostshipGained";
|
||||
case EventParallelConnection::State::HostshipLost: return "HostshipLost";
|
||||
default: throw ghoul::MissingCaseException();
|
||||
}
|
||||
}(e.state);
|
||||
LINFO(fmt::format("[{}] ParallelConnection ({})", i, state));
|
||||
}
|
||||
|
||||
void log(int i, [[ maybe_unused ]] const EventProfileLoadingFinished& e) {
|
||||
ghoul_assert(e.type == EventProfileLoadingFinished::Type, "Wrong type");
|
||||
LINFO(fmt::format("[{}] ProfileLoadingFinished", i));
|
||||
}
|
||||
|
||||
void log(int i, const EventApplicationShutdown& e) {
|
||||
ghoul_assert(e.type == EventApplicationShutdown::Type, "Wrong type");
|
||||
std::string t = [](EventApplicationShutdown::State state) {
|
||||
switch (state) {
|
||||
case EventApplicationShutdown::State::Started: return "started";
|
||||
case EventApplicationShutdown::State::Aborted: return "aborted";
|
||||
case EventApplicationShutdown::State::Finished: return "finished";
|
||||
default: throw ghoul::MissingCaseException();
|
||||
}
|
||||
}(e.state);
|
||||
LINFO(fmt::format("[{}] ApplicationShutdown", i));
|
||||
}
|
||||
|
||||
void log(int i, const EventScreenSpaceRenderableAdded& e) {
|
||||
ghoul_assert(e.type == EventScreenSpaceRenderableAdded::Type, "Wrong type");
|
||||
LINFO(fmt::format("[{}] ScreenSpaceRenderableAdded: {}", i, e.renderable));
|
||||
}
|
||||
|
||||
void log(int i, const EventScreenSpaceRenderableRemoved& e) {
|
||||
ghoul_assert(e.type == EventScreenSpaceRenderableRemoved::Type, "Wrong type");
|
||||
LINFO(fmt::format("[{}] ScreenSpaceRenderableRemoved: {}", i, e.renderable));
|
||||
}
|
||||
|
||||
void log(int i, const EventCameraFocusTransition& e) {
|
||||
ghoul_assert(e.type == EventCameraFocusTransition::Type, "Wrong type");
|
||||
std::string_view t = [](EventCameraFocusTransition::Transition transition) {
|
||||
switch (transition) {
|
||||
case EventCameraFocusTransition::Transition::Approaching:
|
||||
return "Approaching";
|
||||
case EventCameraFocusTransition::Transition::Reaching:
|
||||
return "Reaching";
|
||||
case EventCameraFocusTransition::Transition::Receding:
|
||||
return "Receding";
|
||||
case EventCameraFocusTransition::Transition::Exiting:
|
||||
return "Exiting";
|
||||
default: throw ghoul::MissingCaseException();
|
||||
}
|
||||
}(e.transition);
|
||||
|
||||
LINFO(fmt::format(
|
||||
"[{}] CameraTransition: {}, {} ({})",
|
||||
i, reinterpret_cast<const void*>(e.camera), e.node, t
|
||||
));
|
||||
}
|
||||
|
||||
void log(int i, const EventTimeOfInterestReached& e) {
|
||||
ghoul_assert(e.type == EventTimeOfInterestReached::Type, "Wrong type");
|
||||
LINFO(fmt::format(
|
||||
"[{}] TimeOfInterestReached: {}, {}",
|
||||
i, e.time->UTC(), reinterpret_cast<const void*>(e.camera)
|
||||
));
|
||||
}
|
||||
|
||||
void log(int i, [[ maybe_unused ]] const EventMissionEventReached& e) {
|
||||
ghoul_assert(e.type == EventMissionEventReached::Type, "Wrong type");
|
||||
LINFO(fmt::format("[{}] MissionEventReached", i));
|
||||
}
|
||||
|
||||
void log(int i, const EventPlanetEclipsed& e) {
|
||||
ghoul_assert(e.type == EventPlanetEclipsed::Type, "Wrong type");
|
||||
LINFO(fmt::format("[{}] PlanetEclipsed: {} -> {}", i, e.eclipsee, e.eclipser));
|
||||
}
|
||||
|
||||
void log(int i, [[ maybe_unused ]] const EventInterpolationFinished& e) {
|
||||
ghoul_assert(e.type == EventInterpolationFinished::Type, "Wrong type");
|
||||
LINFO(fmt::format("[{}] InterpolationFinished", i));
|
||||
}
|
||||
|
||||
void log(int i, const EventFocusNodeChanged& e) {
|
||||
ghoul_assert(e.type == EventFocusNodeChanged::Type, "Wrong type");
|
||||
LINFO(fmt::format("[{}] FocusNodeChanged: {} -> {}", i, e.oldNode, e.newNode));
|
||||
}
|
||||
|
||||
void log(int i, const EventLayerAdded& e) {
|
||||
ghoul_assert(e.type == EventLayerAdded::Type, "Wrong type");
|
||||
LINFO(fmt::format("[{}] LayerAdded: {}", i, e.layer));
|
||||
}
|
||||
|
||||
void log(int i, const EventLayerRemoved& e) {
|
||||
ghoul_assert(e.type == EventLayerRemoved::Type, "Wrong type");
|
||||
LINFO(fmt::format("[{}] LayerRemoved: {}", i, e.layer));
|
||||
}
|
||||
|
||||
void log(int i, const EventSessionRecordingPlayback& e) {
|
||||
ghoul_assert(e.type == EventSessionRecordingPlayback::Type, "Wrong type");
|
||||
|
||||
std::string_view state = [](EventSessionRecordingPlayback::State s) {
|
||||
switch (s) {
|
||||
case EventSessionRecordingPlayback::State::Started: return "Started";
|
||||
case EventSessionRecordingPlayback::State::Paused: return "Paused";
|
||||
case EventSessionRecordingPlayback::State::Resumed: return "Resumed";
|
||||
case EventSessionRecordingPlayback::State::Finished: return "Finished";
|
||||
default: throw ghoul::MissingCaseException();
|
||||
}
|
||||
}(e.state);
|
||||
|
||||
LINFO(fmt::format("[{}] SessionRecordingPlayback: {}", i, state));
|
||||
}
|
||||
|
||||
void log(int i, const CustomEvent& e) {
|
||||
ghoul_assert(e.type == CustomEvent::Type, "Wrong type");
|
||||
LINFO(fmt::format("[{}] CustomEvent: {} ({})", i, e.subtype, e.payload));
|
||||
}
|
||||
|
||||
std::string_view toString(Event::Type type) {
|
||||
switch (type) {
|
||||
case Event::Type::SceneGraphNodeAdded: return "SceneGraphNodeAdded";
|
||||
case Event::Type::SceneGraphNodeRemoved: return "SceneGraphNodeRemoved";
|
||||
case Event::Type::ParallelConnection: return "ParallelConnection";
|
||||
case Event::Type::ProfileLoadingFinished: return "ProfileLoadingFinished";
|
||||
case Event::Type::ApplicationShutdown: return "ApplicationShutdown";
|
||||
case Event::Type::ScreenSpaceRenderableAdded: return "ScreenSpaceRenderableAdded";
|
||||
case Event::Type::ScreenSpaceRenderableRemoved:
|
||||
return "ScreenSpaceRenderableRemoved";
|
||||
case Event::Type::CameraFocusTransition: return "CameraFocusTransition";
|
||||
case Event::Type::TimeOfInterestReached: return "TimeOfInterestReached";
|
||||
case Event::Type::MissionEventReached: return "MissionEventReached";
|
||||
case Event::Type::PlanetEclipsed: return "PlanetEclipsed";
|
||||
case Event::Type::InterpolationFinished: return "InterpolationFinished";
|
||||
case Event::Type::FocusNodeChanged: return "FocusNodeChanged";
|
||||
case Event::Type::LayerAdded: return "LayerAdded";
|
||||
case Event::Type::LayerRemoved: return "LayerRemoved";
|
||||
case Event::Type::SessionRecordingPlayback: return "SessionRecordingPlayback";
|
||||
case Event::Type::Custom: return "Custom";
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}
|
||||
|
||||
Event::Type fromString(std::string_view str) {
|
||||
if (str == "SceneGraphNodeAdded") {
|
||||
return Event::Type::SceneGraphNodeAdded;
|
||||
}
|
||||
else if (str == "SceneGraphNodeRemoved") {
|
||||
return Event::Type::SceneGraphNodeRemoved;
|
||||
}
|
||||
else if (str == "ParallelConnection") {
|
||||
return Event::Type::ParallelConnection;
|
||||
}
|
||||
else if (str == "ProfileLoadingFinished") {
|
||||
return Event::Type::ProfileLoadingFinished;
|
||||
}
|
||||
else if (str == "ApplicationShutdown") {
|
||||
return Event::Type::ApplicationShutdown;
|
||||
}
|
||||
else if (str == "ScreenSpaceRenderableAdded") {
|
||||
return Event::Type::ScreenSpaceRenderableAdded;
|
||||
}
|
||||
else if (str == "ScreenSpaceRenderableRemoved") {
|
||||
return Event::Type::ScreenSpaceRenderableRemoved;
|
||||
}
|
||||
else if (str == "CameraFocusTransition") {
|
||||
return Event::Type::CameraFocusTransition;
|
||||
}
|
||||
else if (str == "TimeOfInterestReached") {
|
||||
return Event::Type::TimeOfInterestReached;
|
||||
}
|
||||
else if (str == "MissionEventReached") {
|
||||
return Event::Type::MissionEventReached;
|
||||
}
|
||||
else if (str == "PlanetEclipsed") {
|
||||
return Event::Type::PlanetEclipsed;
|
||||
}
|
||||
else if (str == "InterpolationFinished") {
|
||||
return Event::Type::InterpolationFinished;
|
||||
}
|
||||
else if (str == "FocusNodeChanged") {
|
||||
return Event::Type::FocusNodeChanged;
|
||||
}
|
||||
else if (str == "LayerAdded") {
|
||||
return Event::Type::LayerAdded;
|
||||
}
|
||||
else if (str == "LayerRemoved") {
|
||||
return Event::Type::LayerRemoved;
|
||||
}
|
||||
else if (str == "SessionRecordingPlayback") {
|
||||
return Event::Type::SessionRecordingPlayback;
|
||||
}
|
||||
else if (str == "Custom") {
|
||||
return Event::Type::Custom;
|
||||
}
|
||||
|
||||
throw ghoul::RuntimeError(fmt::format("Unknown event type '{}'", str));
|
||||
}
|
||||
|
||||
ghoul::Dictionary toParameter(const Event& e) {
|
||||
ghoul::Dictionary d;
|
||||
switch (e.type) {
|
||||
case Event::Type::SceneGraphNodeAdded:
|
||||
d.setValue(
|
||||
"Node",
|
||||
std::string(static_cast<const EventSceneGraphNodeAdded&>(e).node)
|
||||
);
|
||||
break;
|
||||
case Event::Type::SceneGraphNodeRemoved:
|
||||
d.setValue(
|
||||
"Node",
|
||||
std::string(static_cast<const EventSceneGraphNodeRemoved&>(e).node)
|
||||
);
|
||||
break;
|
||||
case Event::Type::ParallelConnection:
|
||||
switch (static_cast<const EventParallelConnection&>(e).state) {
|
||||
case EventParallelConnection::State::Established:
|
||||
d.setValue("State", "Established"s);
|
||||
break;
|
||||
case EventParallelConnection::State::Lost:
|
||||
d.setValue("State", "Lost"s);
|
||||
break;
|
||||
case EventParallelConnection::State::HostshipGained:
|
||||
d.setValue("State", "HostshipGained"s);
|
||||
break;
|
||||
case EventParallelConnection::State::HostshipLost:
|
||||
d.setValue("State", "HostshipLost"s);
|
||||
break;
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
break;
|
||||
case Event::Type::ApplicationShutdown:
|
||||
switch (static_cast<const EventApplicationShutdown&>(e).state) {
|
||||
case EventApplicationShutdown::State::Started:
|
||||
d.setValue("State", "Started"s);
|
||||
break;
|
||||
case EventApplicationShutdown::State::Aborted:
|
||||
d.setValue("State", "Aborted"s);
|
||||
break;
|
||||
case EventApplicationShutdown::State::Finished:
|
||||
d.setValue("State", "Finished"s);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Event::Type::ScreenSpaceRenderableAdded:
|
||||
d.setValue(
|
||||
"Renderable",
|
||||
std::string(
|
||||
static_cast<const EventScreenSpaceRenderableAdded&>(e).renderable
|
||||
)
|
||||
);
|
||||
break;
|
||||
case Event::Type::ScreenSpaceRenderableRemoved:
|
||||
d.setValue(
|
||||
"Renderable",
|
||||
std::string(
|
||||
static_cast<const EventScreenSpaceRenderableRemoved&>(e).renderable
|
||||
)
|
||||
);
|
||||
break;
|
||||
case Event::Type::CameraFocusTransition:
|
||||
d.setValue(
|
||||
"Node",
|
||||
std::string(static_cast<const EventCameraFocusTransition&>(e).node)
|
||||
);
|
||||
switch (static_cast<const EventCameraFocusTransition&>(e).transition) {
|
||||
case EventCameraFocusTransition::Transition::Approaching:
|
||||
d.setValue("Transition", "Approaching"s);
|
||||
break;
|
||||
case EventCameraFocusTransition::Transition::Reaching:
|
||||
d.setValue("Transition", "Reaching"s);
|
||||
break;
|
||||
case EventCameraFocusTransition::Transition::Receding:
|
||||
d.setValue("Transition", "Receding"s);
|
||||
break;
|
||||
case EventCameraFocusTransition::Transition::Exiting:
|
||||
d.setValue("Transition", "Exiting"s);
|
||||
break;
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
break;
|
||||
case Event::Type::PlanetEclipsed:
|
||||
d.setValue(
|
||||
"Eclipsee",
|
||||
std::string(static_cast<const EventPlanetEclipsed&>(e).eclipsee)
|
||||
);
|
||||
d.setValue(
|
||||
"Eclipser",
|
||||
std::string(static_cast<const EventPlanetEclipsed&>(e).eclipser)
|
||||
);
|
||||
break;
|
||||
case Event::Type::InterpolationFinished:
|
||||
d.setValue(
|
||||
"Property",
|
||||
std::string(static_cast<const EventInterpolationFinished&>(e).property)
|
||||
);
|
||||
break;
|
||||
case Event::Type::FocusNodeChanged:
|
||||
d.setValue(
|
||||
"OldNode",
|
||||
std::string(static_cast<const EventFocusNodeChanged&>(e).oldNode)
|
||||
);
|
||||
d.setValue(
|
||||
"NewNode",
|
||||
std::string(static_cast<const EventFocusNodeChanged&>(e).newNode)
|
||||
);
|
||||
break;
|
||||
case Event::Type::LayerAdded:
|
||||
d.setValue(
|
||||
"Globe",
|
||||
std::string(static_cast<const EventLayerAdded&>(e).node)
|
||||
);
|
||||
d.setValue(
|
||||
"Group",
|
||||
std::string(static_cast<const EventLayerAdded&>(e).layerGroup)
|
||||
);
|
||||
d.setValue(
|
||||
"Layer",
|
||||
std::string(static_cast<const EventLayerAdded&>(e).layer)
|
||||
);
|
||||
break;
|
||||
case Event::Type::LayerRemoved:
|
||||
d.setValue(
|
||||
"Globe",
|
||||
std::string(static_cast<const EventLayerRemoved&>(e).node)
|
||||
);
|
||||
d.setValue(
|
||||
"Group",
|
||||
std::string(static_cast<const EventLayerRemoved&>(e).layerGroup)
|
||||
);
|
||||
d.setValue(
|
||||
"Layer",
|
||||
std::string(static_cast<const EventLayerRemoved&>(e).layer)
|
||||
);
|
||||
break;
|
||||
case Event::Type::SessionRecordingPlayback:
|
||||
switch (static_cast<const EventSessionRecordingPlayback&>(e).state) {
|
||||
case EventSessionRecordingPlayback::State::Started:
|
||||
d.setValue("State", "Started"s);
|
||||
break;
|
||||
case EventSessionRecordingPlayback::State::Paused:
|
||||
d.setValue("State", "Paused"s);
|
||||
break;
|
||||
case EventSessionRecordingPlayback::State::Resumed:
|
||||
d.setValue("State", "Resumed"s);
|
||||
break;
|
||||
case EventSessionRecordingPlayback::State::Finished:
|
||||
d.setValue("State", "Finished"s);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Event::Type::Custom:
|
||||
d.setValue(
|
||||
"Subtype", std::string(static_cast<const CustomEvent&>(e).subtype)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
void logAllEvents(const Event* e) {
|
||||
int i = 0;
|
||||
while (e) {
|
||||
switch (e->type) {
|
||||
case Event::Type::SceneGraphNodeAdded:
|
||||
log(i, *static_cast<const EventSceneGraphNodeAdded*>(e));
|
||||
break;
|
||||
case Event::Type::SceneGraphNodeRemoved:
|
||||
log(i, *static_cast<const EventSceneGraphNodeRemoved*>(e));
|
||||
break;
|
||||
case Event::Type::ParallelConnection:
|
||||
log(i, *static_cast<const EventParallelConnection*>(e));
|
||||
break;
|
||||
case Event::Type::ProfileLoadingFinished:
|
||||
log(i, *static_cast<const EventProfileLoadingFinished*>(e));
|
||||
break;
|
||||
case Event::Type::ApplicationShutdown:
|
||||
log(i, *static_cast<const EventApplicationShutdown*>(e));
|
||||
break;
|
||||
case Event::Type::ScreenSpaceRenderableAdded:
|
||||
log(i, *static_cast<const EventScreenSpaceRenderableAdded*>(e));
|
||||
break;
|
||||
case Event::Type::ScreenSpaceRenderableRemoved:
|
||||
log(i, *static_cast<const EventScreenSpaceRenderableRemoved*>(e));
|
||||
break;
|
||||
case Event::Type::CameraFocusTransition:
|
||||
log(i, *static_cast<const EventCameraFocusTransition*>(e));
|
||||
break;
|
||||
case Event::Type::TimeOfInterestReached:
|
||||
log(i, *static_cast<const EventTimeOfInterestReached*>(e));
|
||||
break;
|
||||
case Event::Type::MissionEventReached:
|
||||
log(i, *static_cast<const EventMissionEventReached*>(e));
|
||||
break;
|
||||
case Event::Type::PlanetEclipsed:
|
||||
log(i, *static_cast<const EventPlanetEclipsed*>(e));
|
||||
break;
|
||||
case Event::Type::InterpolationFinished:
|
||||
log(i, *static_cast<const EventInterpolationFinished*>(e));
|
||||
break;
|
||||
case Event::Type::FocusNodeChanged:
|
||||
log(i, *static_cast<const EventFocusNodeChanged*>(e));
|
||||
break;
|
||||
case Event::Type::LayerAdded:
|
||||
log(i, *static_cast<const EventLayerAdded*>(e));
|
||||
break;
|
||||
case Event::Type::LayerRemoved:
|
||||
log(i, *static_cast<const EventLayerRemoved*>(e));
|
||||
break;
|
||||
case Event::Type::SessionRecordingPlayback:
|
||||
log(i, *static_cast<const EventSessionRecordingPlayback*>(e));
|
||||
break;
|
||||
case Event::Type::Custom:
|
||||
log(i, *static_cast<const CustomEvent*>(e));
|
||||
break;
|
||||
default:
|
||||
LINFO(fmt::format("[{}]: Unknown {}", typeid(e).name()));
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
e = e->next;
|
||||
}
|
||||
}
|
||||
|
||||
EventSceneGraphNodeAdded::EventSceneGraphNodeAdded(const SceneGraphNode* node_)
|
||||
: Event(Type)
|
||||
, node(temporaryString(node_->identifier()))
|
||||
{}
|
||||
|
||||
EventSceneGraphNodeRemoved::EventSceneGraphNodeRemoved(const SceneGraphNode* node_)
|
||||
: Event(Type)
|
||||
, node(temporaryString(node_->identifier()))
|
||||
{}
|
||||
|
||||
EventParallelConnection::EventParallelConnection(State state_)
|
||||
: Event(Type)
|
||||
, state(state_)
|
||||
{}
|
||||
|
||||
EventProfileLoadingFinished::EventProfileLoadingFinished()
|
||||
: Event(Type)
|
||||
{}
|
||||
|
||||
EventApplicationShutdown::EventApplicationShutdown(State state_)
|
||||
: Event(Type)
|
||||
, state(state_)
|
||||
{}
|
||||
|
||||
EventScreenSpaceRenderableAdded::EventScreenSpaceRenderableAdded(
|
||||
const ScreenSpaceRenderable* renderable_)
|
||||
: Event(Type)
|
||||
, renderable(temporaryString(renderable_->identifier()))
|
||||
{}
|
||||
|
||||
EventScreenSpaceRenderableRemoved::EventScreenSpaceRenderableRemoved(
|
||||
const ScreenSpaceRenderable* renderable_)
|
||||
: Event(Type)
|
||||
, renderable(temporaryString(renderable_->identifier()))
|
||||
{}
|
||||
|
||||
EventCameraFocusTransition::EventCameraFocusTransition(const Camera* camera_,
|
||||
const SceneGraphNode* node_,
|
||||
Transition transition_)
|
||||
: Event(Type)
|
||||
, camera(camera_)
|
||||
, node(temporaryString(node_->identifier()))
|
||||
, transition(transition_)
|
||||
{}
|
||||
|
||||
EventTimeOfInterestReached::EventTimeOfInterestReached(const Time* time_,
|
||||
const Camera* camera_)
|
||||
: Event(Type)
|
||||
, time(time_)
|
||||
, camera(camera_)
|
||||
{}
|
||||
|
||||
EventMissionEventReached::EventMissionEventReached()
|
||||
: Event(Type)
|
||||
{}
|
||||
|
||||
EventPlanetEclipsed::EventPlanetEclipsed(const SceneGraphNode* eclipsee_,
|
||||
const SceneGraphNode* eclipser_)
|
||||
: Event(Type)
|
||||
, eclipsee(temporaryString(eclipsee_->identifier()))
|
||||
, eclipser(temporaryString(eclipser_->identifier()))
|
||||
{}
|
||||
|
||||
EventInterpolationFinished::EventInterpolationFinished(
|
||||
const properties::Property* property_)
|
||||
: Event(Type)
|
||||
, property(temporaryString(property_->fullyQualifiedIdentifier()))
|
||||
{}
|
||||
|
||||
EventFocusNodeChanged::EventFocusNodeChanged(const SceneGraphNode* oldNode_,
|
||||
const SceneGraphNode* newNode_)
|
||||
: Event(Type)
|
||||
, oldNode(oldNode_ ? temporaryString(oldNode_->identifier()) : "")
|
||||
, newNode(temporaryString(newNode_->identifier()))
|
||||
{
|
||||
ghoul_assert(newNode_, "There must be a new node");
|
||||
}
|
||||
|
||||
EventLayerAdded::EventLayerAdded(std::string_view node_, std::string_view layerGroup_,
|
||||
std::string_view layer_)
|
||||
: Event(Type)
|
||||
, node(temporaryString(node_))
|
||||
, layerGroup(temporaryString(layerGroup_))
|
||||
, layer(temporaryString(layer_))
|
||||
{}
|
||||
|
||||
EventLayerRemoved::EventLayerRemoved(std::string_view node_, std::string_view layerGroup_,
|
||||
std::string_view layer_)
|
||||
: Event(Type)
|
||||
, node(temporaryString(node_))
|
||||
, layerGroup(temporaryString(layerGroup_))
|
||||
, layer(temporaryString(layer_))
|
||||
{}
|
||||
|
||||
EventSessionRecordingPlayback::EventSessionRecordingPlayback(State state_)
|
||||
: Event(Type)
|
||||
, state(state_)
|
||||
{}
|
||||
|
||||
CustomEvent::CustomEvent(std::string_view subtype_, const void* payload_)
|
||||
: Event(Type)
|
||||
, subtype(subtype_)
|
||||
, payload(payload_)
|
||||
{}
|
||||
|
||||
} // namespace openspace::events
|
||||
@@ -0,0 +1,133 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* 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/events/eventengine.h>
|
||||
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/interaction/actionmanager.h>
|
||||
|
||||
#include "eventengine_lua.inl"
|
||||
|
||||
namespace openspace {
|
||||
|
||||
#ifdef _DEBUG
|
||||
uint64_t EventEngine::nEvents = 0;
|
||||
#endif // _DEBUG
|
||||
|
||||
events::Event* EventEngine::firstEvent() const {
|
||||
return _firstEvent;
|
||||
}
|
||||
|
||||
void EventEngine::postFrameCleanup() {
|
||||
_memory.reset();
|
||||
_firstEvent = nullptr;
|
||||
_lastEvent = nullptr;
|
||||
#ifdef _DEBUG
|
||||
nEvents = 0;
|
||||
#endif // _DEBUG
|
||||
}
|
||||
|
||||
void EventEngine::registerEventAction(events::Event::Type type,
|
||||
std::string identifier,
|
||||
std::optional<ghoul::Dictionary> filter)
|
||||
{
|
||||
ActionInfo ai;
|
||||
ai.action = std::move(identifier);
|
||||
ai.filter = std::move(filter);
|
||||
const auto it = _eventActions.find(type);
|
||||
if (it != _eventActions.end()) {
|
||||
it->second.push_back(ai);
|
||||
}
|
||||
else {
|
||||
_eventActions[type] = { std::move(ai) };
|
||||
}
|
||||
}
|
||||
|
||||
void EventEngine::unregisterEventAction(events::Event::Type type,
|
||||
const std::string& identifier,
|
||||
std::optional<ghoul::Dictionary> filter)
|
||||
{
|
||||
const auto it = _eventActions.find(type);
|
||||
if (it != _eventActions.end()) {
|
||||
const auto jt = std::find_if(
|
||||
it->second.begin(), it->second.end(),
|
||||
[identifier, filter](const ActionInfo& ai) {
|
||||
const bool a = ai.action == identifier;
|
||||
const bool f = !filter.has_value() || *filter == ai.filter;
|
||||
return a && f;
|
||||
}
|
||||
);
|
||||
if (jt != it->second.end()) {
|
||||
it->second.erase(jt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EventEngine::triggerActions() const {
|
||||
if (_eventActions.empty()) {
|
||||
// Nothing to do here
|
||||
return;
|
||||
}
|
||||
|
||||
const events::Event* e = _firstEvent;
|
||||
while (e) {
|
||||
const auto it = _eventActions.find(e->type);
|
||||
if (it != _eventActions.end()) {
|
||||
ghoul::Dictionary params = toParameter(*e);
|
||||
for (const ActionInfo& ai : it->second) {
|
||||
if (!ai.filter.has_value() || params.isSubset(*ai.filter)) {
|
||||
global::actionManager->triggerAction(ai.action, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
e = e->next;
|
||||
}
|
||||
}
|
||||
|
||||
scripting::LuaLibrary EventEngine::luaLibrary() {
|
||||
scripting::LuaLibrary res;
|
||||
res.name = "event";
|
||||
res.functions.push_back({
|
||||
"registerEventAction",
|
||||
&luascriptfunctions::registerEventAction,
|
||||
{},
|
||||
"string, string [, table]",
|
||||
"Registers an action (second parameter) to be executed whenever an event (first "
|
||||
"parameter) is encountered. If the optional third parameter is provided, it "
|
||||
"describes a filter that the event is being checked against and only if it "
|
||||
"passes the filter, the action is triggered"
|
||||
});
|
||||
res.functions.push_back({
|
||||
"unregisterEventAction",
|
||||
&luascriptfunctions::unregisterEventAction,
|
||||
{},
|
||||
"string, string [, table]",
|
||||
"Unregisters a specific combination of event (first parameter), action (second "
|
||||
"parameter), and potentially a filter (optional third argument)"
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
@@ -0,0 +1,49 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
namespace openspace::luascriptfunctions {
|
||||
|
||||
int registerEventAction(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 2, 3 }, "lua::registerEventAction");
|
||||
auto [event, action, filter] =
|
||||
ghoul::lua::values<std::string, std::string, std::optional<ghoul::Dictionary>>(L);
|
||||
|
||||
events::Event::Type type = events::fromString(event);
|
||||
|
||||
global::eventEngine->registerEventAction(type, std::move(action), std::move(filter));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unregisterEventAction(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 2, 3 }, "lua::unregisterEventAction");
|
||||
auto [event, action, filter] =
|
||||
ghoul::lua::values<std::string, std::string, std::optional<ghoul::Dictionary>>(L);
|
||||
|
||||
events::Event::Type type = events::fromString(event);
|
||||
|
||||
global::eventEngine->unregisterEventAction(type, action, filter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace openspace::luascriptfunctions
|
||||
@@ -86,7 +86,14 @@ void ActionManager::triggerAction(const std::string& identifier,
|
||||
const ghoul::Dictionary& arguments) const
|
||||
{
|
||||
ghoul_assert(!identifier.empty(), "Identifier must not be empty");
|
||||
ghoul_assert(hasAction(identifier), "Action was not found in the list");
|
||||
|
||||
if (!hasAction(identifier)) {
|
||||
LWARNINGC(
|
||||
"ActionManager",
|
||||
fmt::format("Action '{}' not found in the list", identifier)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const Action& a = action(identifier);
|
||||
if (arguments.isEmpty()) {
|
||||
@@ -97,7 +104,7 @@ void ActionManager::triggerAction(const std::string& identifier,
|
||||
}
|
||||
else {
|
||||
global::scriptEngine->queueScript(
|
||||
fmt::format("local args = {}\n{}", ghoul::formatLua(arguments), a.command),
|
||||
fmt::format("args = {}\n{}", ghoul::formatLua(arguments), a.command),
|
||||
scripting::ScriptEngine::RemoteScripting(a.synchronization)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ int actions(lua_State* L) {
|
||||
action.synchronization == interaction::Action::IsSynchronized::Yes
|
||||
);
|
||||
lua_settable(L, -3);
|
||||
|
||||
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <openspace/camera/camera.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/events/eventengine.h>
|
||||
#include <openspace/interaction/tasks/convertrecfileversiontask.h>
|
||||
#include <openspace/interaction/tasks/convertrecformattask.h>
|
||||
#include <openspace/navigation/keyframenavigator.h>
|
||||
@@ -461,6 +462,9 @@ bool SessionRecording::startPlayback(std::string& filename,
|
||||
(_playbackForceSimTimeAtStart ? 1 : 0)
|
||||
));
|
||||
|
||||
global::eventEngine->publishEvent<events::EventSessionRecordingPlayback>(
|
||||
events::EventSessionRecordingPlayback::State::Started
|
||||
);
|
||||
initializePlayback_triggerStart();
|
||||
|
||||
global::navigationHandler->orbitalNavigator().updateOnCameraInteraction();
|
||||
@@ -527,12 +531,18 @@ void SessionRecording::setPlaybackPause(bool pause) {
|
||||
global::timeManager->setPause(true);
|
||||
}
|
||||
_state = SessionState::PlaybackPaused;
|
||||
global::eventEngine->publishEvent<events::EventSessionRecordingPlayback>(
|
||||
events::EventSessionRecordingPlayback::State::Paused
|
||||
);
|
||||
}
|
||||
else if (!pause && _state == SessionState::PlaybackPaused) {
|
||||
if (!_playbackPausedWithinDeltaTimePause) {
|
||||
global::timeManager->setPause(false);
|
||||
}
|
||||
_state = SessionState::Playback;
|
||||
global::eventEngine->publishEvent<events::EventSessionRecordingPlayback>(
|
||||
events::EventSessionRecordingPlayback::State::Resumed
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,7 +585,7 @@ void SessionRecording::signalPlaybackFinishedForComponent(RecordedType type) {
|
||||
|
||||
if (!_playbackActive_camera && !_playbackActive_time && !_playbackActive_script) {
|
||||
if (_playbackLoopMode) {
|
||||
//Loop back to the beginning to replay
|
||||
// Loop back to the beginning to replay
|
||||
_saveRenderingDuringPlayback = false;
|
||||
initializePlayback_time(global::windowDelegate->applicationTime());
|
||||
initializePlayback_modeFlags();
|
||||
@@ -586,6 +596,9 @@ void SessionRecording::signalPlaybackFinishedForComponent(RecordedType type) {
|
||||
_state = SessionState::Idle;
|
||||
_cleanupNeeded = true;
|
||||
LINFO("Playback session finished");
|
||||
global::eventEngine->publishEvent<events::EventSessionRecordingPlayback>(
|
||||
events::EventSessionRecordingPlayback::State::Finished
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -606,6 +619,9 @@ void SessionRecording::stopPlayback() {
|
||||
_state = SessionState::Idle;
|
||||
_cleanupNeeded = true;
|
||||
LINFO("Session playback stopped");
|
||||
global::eventEngine->publishEvent<events::EventSessionRecordingPlayback>(
|
||||
events::EventSessionRecordingPlayback::State::Finished
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1963,9 +1979,13 @@ bool SessionRecording::processCameraKeyframe(double now) {
|
||||
}
|
||||
|
||||
// getPrevTimestamp();
|
||||
double prevTime = appropriateTimestamp(_timeline[_idxTimeline_cameraPtrPrev].t3stamps);
|
||||
double prevTime = appropriateTimestamp(
|
||||
_timeline[_idxTimeline_cameraPtrPrev].t3stamps
|
||||
);
|
||||
// getNextTimestamp();
|
||||
double nextTime = appropriateTimestamp(_timeline[_idxTimeline_cameraPtrNext].t3stamps);
|
||||
double nextTime = appropriateTimestamp(
|
||||
_timeline[_idxTimeline_cameraPtrNext].t3stamps
|
||||
);
|
||||
|
||||
double t;
|
||||
if ((nextTime - prevTime) < 1e-7) {
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#include <openspace/camera/camera.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/events/event.h>
|
||||
#include <openspace/events/eventengine.h>
|
||||
#include <openspace/interaction/actionmanager.h>
|
||||
#include <openspace/navigation/navigationstate.h>
|
||||
#include <openspace/network/parallelpeer.h>
|
||||
#include <openspace/scene/profile.h>
|
||||
@@ -175,6 +178,7 @@ void NavigationHandler::updateCamera(double deltaTime) {
|
||||
}
|
||||
else if (_pathNavigator.isPlayingPath()) {
|
||||
_pathNavigator.updateCamera(deltaTime);
|
||||
updateCameraTransitions();
|
||||
}
|
||||
else {
|
||||
if (_disableJoystickInputs) {
|
||||
@@ -186,6 +190,7 @@ void NavigationHandler::updateCamera(double deltaTime) {
|
||||
}
|
||||
_orbitalNavigator.updateStatesFromInput(_inputState, deltaTime);
|
||||
_orbitalNavigator.updateCameraStateFromStates(deltaTime);
|
||||
updateCameraTransitions();
|
||||
}
|
||||
|
||||
_orbitalNavigator.updateCameraScalingFromAnchor(deltaTime);
|
||||
@@ -208,6 +213,118 @@ void NavigationHandler::applyNavigationState(const NavigationState& ns) {
|
||||
_orbitalNavigator.clearPreviousState();
|
||||
}
|
||||
|
||||
void NavigationHandler::updateCameraTransitions() {
|
||||
// This function is concerned with managing transitions of the camera between
|
||||
// different distances of interest relative to the focus node. For each transition two
|
||||
// scenarios are handled; SceneGraphNodes can have attached actions for each
|
||||
// transition, which are automatically triggered. Additionally, an
|
||||
// EventCameraTransition event is fired that contains information about the focus node
|
||||
// and the transition state that caused the vent to fire.
|
||||
|
||||
// Diagram of events for a camera moving from right-to-left.
|
||||
// Interaction sphere is 'O' in middle, and ')' are spherical boundaries. The approach
|
||||
// factor, reach factor, and interaction sphere radius are all taken from the current
|
||||
// focus node.
|
||||
//
|
||||
// |<------------------->| Approach factor * Interaction sphere
|
||||
// |<------>| Reach Factor * Interaction sphere
|
||||
//
|
||||
// ( ( O ) )
|
||||
// ^ ^ ^ ^
|
||||
// OnExit OnMoveAway OnReach OnApproach
|
||||
const glm::dvec3 anchorPos = anchorNode()->worldPosition();
|
||||
const glm::dvec3 cameraPos = _camera->positionVec3();
|
||||
const double currDistance = glm::distance(anchorPos, cameraPos);
|
||||
const double d = anchorNode()->interactionSphere();
|
||||
const double af = anchorNode()->approachFactor();
|
||||
const double rf = anchorNode()->reachFactor();
|
||||
|
||||
using namespace std::string_literals;
|
||||
if (_inAnchorApproachSphere) {
|
||||
if (currDistance > d * (af + InteractionHystersis)) {
|
||||
// We left the approach sphere outwards
|
||||
_inAnchorApproachSphere = false;
|
||||
|
||||
if (!anchorNode()->onExitAction().empty()) {
|
||||
ghoul::Dictionary dict;
|
||||
dict.setValue("Node", anchorNode()->identifier());
|
||||
dict.setValue("Transition", "Exiting"s);
|
||||
for (const std::string& action : anchorNode()->onExitAction()) {
|
||||
global::actionManager->triggerAction(action, dict);
|
||||
}
|
||||
}
|
||||
|
||||
global::eventEngine->publishEvent<events::EventCameraFocusTransition>(
|
||||
_camera,
|
||||
anchorNode(),
|
||||
events::EventCameraFocusTransition::Transition::Exiting
|
||||
);
|
||||
}
|
||||
else if (currDistance < d * (rf - InteractionHystersis)) {
|
||||
// We transitioned from the approach sphere into the reach sphere
|
||||
_inAnchorApproachSphere = false;
|
||||
_inAnchorReachSphere = true;
|
||||
|
||||
if (!anchorNode()->onReachAction().empty()) {
|
||||
ghoul::Dictionary dict;
|
||||
dict.setValue("Node", anchorNode()->identifier());
|
||||
dict.setValue("Transition", "Reaching"s);
|
||||
for (const std::string& action : anchorNode()->onReachAction()) {
|
||||
global::actionManager->triggerAction(action, dict);
|
||||
}
|
||||
}
|
||||
|
||||
global::eventEngine->publishEvent<events::EventCameraFocusTransition>(
|
||||
_camera,
|
||||
anchorNode(),
|
||||
events::EventCameraFocusTransition::Transition::Reaching
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (_inAnchorReachSphere && currDistance > d * (rf + InteractionHystersis)) {
|
||||
// We transitioned from the reach sphere to the approach sphere
|
||||
_inAnchorReachSphere = false;
|
||||
_inAnchorApproachSphere = true;
|
||||
|
||||
if (!anchorNode()->onRecedeAction().empty()) {
|
||||
ghoul::Dictionary dict;
|
||||
dict.setValue("Node", anchorNode()->identifier());
|
||||
dict.setValue("Transition", "Receding"s);
|
||||
for (const std::string& action : anchorNode()->onRecedeAction()) {
|
||||
global::actionManager->triggerAction(action, dict);
|
||||
}
|
||||
}
|
||||
|
||||
global::eventEngine->publishEvent<events::EventCameraFocusTransition>(
|
||||
_camera,
|
||||
anchorNode(),
|
||||
events::EventCameraFocusTransition::Transition::Receding
|
||||
);
|
||||
}
|
||||
else if (!_inAnchorApproachSphere && !_inAnchorReachSphere &&
|
||||
currDistance < d * (af - InteractionHystersis))
|
||||
{
|
||||
// We moved into the approach sphere
|
||||
_inAnchorApproachSphere = true;
|
||||
|
||||
if (!anchorNode()->onApproachAction().empty()) {
|
||||
ghoul::Dictionary dict;
|
||||
dict.setValue("Node", anchorNode()->identifier());
|
||||
dict.setValue("Transition", "Approaching"s);
|
||||
for (const std::string& action : anchorNode()->onApproachAction()) {
|
||||
global::actionManager->triggerAction(action, dict);
|
||||
}
|
||||
}
|
||||
|
||||
global::eventEngine->publishEvent<events::EventCameraFocusTransition>(
|
||||
_camera,
|
||||
anchorNode(),
|
||||
events::EventCameraFocusTransition::Transition::Approaching
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NavigationHandler::setEnableKeyFrameInteraction() {
|
||||
_useKeyFrameInteraction = true;
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ int bindJoystickButton(lua_State* L) {
|
||||
actionStr = actionStr.value_or("Press");
|
||||
isRemote = isRemote.value_or(true);
|
||||
|
||||
interaction::JoystickAction action =
|
||||
interaction::JoystickAction action =
|
||||
ghoul::from_string<interaction::JoystickAction>(*actionStr);
|
||||
|
||||
global::navigationHandler->bindJoystickButtonCommand(
|
||||
|
||||
@@ -80,8 +80,8 @@ NavigationState::NavigationState(const ghoul::Dictionary& dictionary) {
|
||||
}
|
||||
|
||||
NavigationState::NavigationState(std::string anchor_, std::string aim_,
|
||||
std::string referenceFrame_, glm::dvec3 position_,
|
||||
std::optional<glm::dvec3> up_,
|
||||
std::string referenceFrame_, glm::dvec3 position_,
|
||||
std::optional<glm::dvec3> up_,
|
||||
double yaw_, double pitch_)
|
||||
: anchor(std::move(anchor_))
|
||||
, aim(std::move(aim_))
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/events/event.h>
|
||||
#include <openspace/events/eventengine.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/easing.h>
|
||||
#include <glm/gtx/rotate_vector.hpp>
|
||||
@@ -353,7 +356,12 @@ OrbitalNavigator::OrbitalNavigator()
|
||||
}
|
||||
SceneGraphNode* node = sceneGraphNode(_anchor.value());
|
||||
if (node) {
|
||||
const SceneGraphNode* previousAnchor = _anchorNode;
|
||||
setAnchorNode(node);
|
||||
global::eventEngine->publishEvent<events::EventFocusNodeChanged>(
|
||||
previousAnchor,
|
||||
node
|
||||
);
|
||||
}
|
||||
else {
|
||||
LERROR(fmt::format(
|
||||
@@ -455,7 +463,9 @@ OrbitalNavigator::OrbitalNavigator()
|
||||
addPropertySubOwner(_linearFlight);
|
||||
addPropertySubOwner(_idleBehavior);
|
||||
|
||||
_idleBehaviorDampenInterpolator.setTransferFunction(ghoul::quadraticEaseInOut<double>);
|
||||
_idleBehaviorDampenInterpolator.setTransferFunction(
|
||||
ghoul::quadraticEaseInOut<double>
|
||||
);
|
||||
_idleBehavior.dampenInterpolationTime.onChange([&]() {
|
||||
_idleBehaviorDampenInterpolator.setInterpolationTime(
|
||||
_idleBehavior.dampenInterpolationTime
|
||||
@@ -804,8 +814,14 @@ glm::dvec3 OrbitalNavigator::cameraToSurfaceVector(const glm::dvec3& cameraPos,
|
||||
void OrbitalNavigator::setFocusNode(const SceneGraphNode* focusNode,
|
||||
bool resetVelocitiesOnChange)
|
||||
{
|
||||
const SceneGraphNode* previousAnchor = _anchorNode;
|
||||
setAnchorNode(focusNode, resetVelocitiesOnChange);
|
||||
setAimNode(nullptr);
|
||||
|
||||
global::eventEngine->publishEvent<events::EventFocusNodeChanged>(
|
||||
previousAnchor,
|
||||
focusNode
|
||||
);
|
||||
}
|
||||
|
||||
void OrbitalNavigator::setFocusNode(const std::string& focusNode, bool) {
|
||||
@@ -953,8 +969,8 @@ bool OrbitalNavigator::shouldFollowAnchorRotation(const glm::dvec3& cameraPositi
|
||||
|
||||
const double distanceToCamera =
|
||||
glm::distance(cameraPosition, _anchorNode->worldPosition());
|
||||
|
||||
return distanceToCamera < maximumDistanceForRotation;
|
||||
bool shouldFollow = distanceToCamera < maximumDistanceForRotation;
|
||||
return shouldFollow;
|
||||
}
|
||||
|
||||
bool OrbitalNavigator::followingAnchorRotation() const {
|
||||
@@ -1617,8 +1633,8 @@ void OrbitalNavigator::applyIdleBehavior(double deltaTime, glm::dvec3& position,
|
||||
break;
|
||||
case IdleBehavior::Behavior::OrbitAtConstantLat: {
|
||||
// Assume that "north" coincides with the local z-direction
|
||||
// @TODO (2021-07-09, emmbr) Make each scene graph node aware of its own
|
||||
// north/up, so that we can query this information rather than assuming it.
|
||||
// @TODO (2021-07-09, emmbr) Make each scene graph node aware of its own
|
||||
// north/up, so that we can query this information rather than assuming it.
|
||||
// The we could also combine this idle behavior with the next
|
||||
const glm::dvec3 north = glm::dvec3(0.0, 0.0, 1.0);
|
||||
orbitAroundAxis(north, deltaTime, position, globalRotation, speedScale);
|
||||
@@ -1658,14 +1674,14 @@ void OrbitalNavigator::orbitAnchor(double deltaTime, glm::dvec3& position,
|
||||
position += rotationDiffVec3;
|
||||
}
|
||||
|
||||
void OrbitalNavigator::orbitAroundAxis(const glm::dvec3 axis, double deltaTime,
|
||||
void OrbitalNavigator::orbitAroundAxis(const glm::dvec3 axis, double deltaTime,
|
||||
glm::dvec3& position, glm::dquat& globalRotation,
|
||||
double speedScale)
|
||||
{
|
||||
ghoul_assert(_anchorNode != nullptr, "Node to orbit must be set!");
|
||||
|
||||
const glm::dmat4 modelTransform = _anchorNode->modelTransform();
|
||||
const glm::dvec3 axisInWorldCoords =
|
||||
const glm::dvec3 axisInWorldCoords =
|
||||
glm::dmat3(modelTransform) * glm::normalize(axis);
|
||||
|
||||
// Compute rotation to be applied around the axis
|
||||
|
||||
@@ -59,7 +59,8 @@ namespace {
|
||||
// The desired duration traversing the specified path segment should take
|
||||
std::optional<float> duration;
|
||||
|
||||
// (Node): The target node of the camera path. Not optional for 'Node' instructions
|
||||
// (Node): The target node of the camera path. Not optional for 'Node'
|
||||
// instructions
|
||||
std::optional<std::string> target;
|
||||
|
||||
// (Node): An optional position in relation to the target node, in model
|
||||
@@ -271,9 +272,11 @@ double Path::speedAlongPath(double traveledDistance) const {
|
||||
speed *= remainingDistance / closeUpDistance + 0.01;
|
||||
}
|
||||
|
||||
// TODO: also dampen speed based on curvature, or make sure the curve has a rounder shape
|
||||
// TODO: also dampen speed based on curvature, or make sure the curve has a rounder
|
||||
// shape
|
||||
|
||||
// TODO: check for when path is shorter than the starUpDistance or closeUpDistance variables
|
||||
// TODO: check for when path is shorter than the starUpDistance or closeUpDistance
|
||||
// variables
|
||||
|
||||
return _speedFactorFromDuration * speed;
|
||||
}
|
||||
@@ -384,7 +387,9 @@ Waypoint computeWaypointFromNodeInfo(const NodeInfo& info, const Waypoint& start
|
||||
if (info.position.has_value()) {
|
||||
// The position in instruction is given in the targetNode's local coordinates.
|
||||
// Convert to world coordinates
|
||||
targetPos = glm::dvec3(targetNode->modelTransform() * glm::dvec4(*info.position, 1.0));
|
||||
targetPos = glm::dvec3(
|
||||
targetNode->modelTransform() * glm::dvec4(*info.position, 1.0)
|
||||
);
|
||||
}
|
||||
else {
|
||||
const double radius = Waypoint::findValidBoundingSphere(targetNode);
|
||||
|
||||
@@ -80,7 +80,8 @@ ZoomOutOverviewCurve::ZoomOutOverviewCurve(const Waypoint& start, const Waypoint
|
||||
goodStepDirection = glm::normalize(n1 + n2);
|
||||
}
|
||||
|
||||
// Find a direction that is orthogonal to the line between the start and end position
|
||||
// Find a direction that is orthogonal to the line between the start and end
|
||||
// position
|
||||
const glm::dvec3 startPosToEndPos = end.position() - start.position();
|
||||
const glm::dvec3 outwardStepVector =
|
||||
0.5 * glm::length(startPosToEndPos) * goodStepDirection;
|
||||
|
||||
@@ -72,7 +72,8 @@ namespace {
|
||||
"triggered once the path has reached its target."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo MinBoundingSphereInfo = {
|
||||
constexpr const openspace::properties::Property::PropertyInfo MinBoundingSphereInfo =
|
||||
{
|
||||
"MinimalValidBoundingSphere",
|
||||
"Minimal Valid Bounding Sphere",
|
||||
"The minimal allowed value for a bounding sphere, in meters. Used for "
|
||||
@@ -203,8 +204,10 @@ void PathNavigator::updateCamera(double deltaTime) {
|
||||
|
||||
if (_applyIdleBehaviorOnFinish) {
|
||||
constexpr const char* ApplyIdleBehaviorScript =
|
||||
"local f = 'NavigationHandler.OrbitalNavigator.IdleBehavior.ApplyIdleBehavior';"
|
||||
"openspace.setPropertyValueSingle(f, true);";
|
||||
"openspace.setPropertyValueSingle("
|
||||
"'NavigationHandler.OrbitalNavigator.IdleBehavior.ApplyIdleBehavior',"
|
||||
"true"
|
||||
");";
|
||||
|
||||
global::scriptEngine->queueScript(
|
||||
ApplyIdleBehaviorScript,
|
||||
|
||||
@@ -86,9 +86,8 @@ int goTo(lua_State* L) {
|
||||
return ghoul::lua::luaError(L, "Unknown node name: " + nodeIdentifier);
|
||||
}
|
||||
|
||||
using namespace std::string_literals;
|
||||
ghoul::Dictionary insDict;
|
||||
insDict.setValue("TargetType", "Node"s);
|
||||
insDict.setValue("TargetType", std::string("Node"));
|
||||
insDict.setValue("Target", nodeIdentifier);
|
||||
if (useUpFromTargetOrDuration.has_value()) {
|
||||
if (std::holds_alternative<bool>(*useUpFromTargetOrDuration)) {
|
||||
@@ -134,9 +133,8 @@ int goToHeight(lua_State* L) {
|
||||
return ghoul::lua::luaError(L, "Unknown node name: " + nodeIdentifier);
|
||||
}
|
||||
|
||||
using namespace std::string_literals;
|
||||
ghoul::Dictionary insDict;
|
||||
insDict.setValue("TargetType", "Node"s);
|
||||
insDict.setValue("TargetType", std::string("Node"));
|
||||
insDict.setValue("Target", nodeIdentifier);
|
||||
insDict.setValue("Height", height);
|
||||
if (useUpFromTargetOrDuration.has_value()) {
|
||||
@@ -190,9 +188,8 @@ int goToNavigationState(lua_State* L) {
|
||||
);
|
||||
}
|
||||
|
||||
using namespace std::string_literals;
|
||||
ghoul::Dictionary instruction;
|
||||
instruction.setValue("TargetType", "NavigationState"s);
|
||||
instruction.setValue("TargetType", std::string("NavigationState"));
|
||||
instruction.setValue("NavigationState", navigationState);
|
||||
|
||||
if (duration.has_value()) {
|
||||
|
||||
@@ -53,7 +53,7 @@ Waypoint::Waypoint(const glm::dvec3& pos, const glm::dquat& rot, const std::stri
|
||||
}
|
||||
|
||||
Waypoint::Waypoint(const NavigationState& ns) {
|
||||
const SceneGraphNode* anchorNode = sceneGraphNode(ns.anchor);
|
||||
const SceneGraphNode* anchorNode = sceneGraphNode(ns.anchor);
|
||||
|
||||
if (!anchorNode) {
|
||||
LERROR(fmt::format("Could not find node '{}' to target", ns.anchor));
|
||||
@@ -92,7 +92,7 @@ double Waypoint::validBoundingSphere() const {
|
||||
double Waypoint::findValidBoundingSphere(const SceneGraphNode* node) {
|
||||
double bs = static_cast<double>(node->boundingSphere());
|
||||
|
||||
const double minValidBoundingSphere =
|
||||
const double minValidBoundingSphere =
|
||||
global::navigationHandler->pathNavigator().minValidBoundingSphere();
|
||||
|
||||
if (bs < minValidBoundingSphere) {
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include <openspace/camera/camera.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/events/event.h>
|
||||
#include <openspace/events/eventengine.h>
|
||||
#include <openspace/navigation/keyframenavigator.h>
|
||||
#include <openspace/navigation/navigationhandler.h>
|
||||
#include <openspace/navigation/orbitalnavigator.h>
|
||||
@@ -215,7 +217,7 @@ void ParallelPeer::handleMessage(const ParallelConnection::Message& message) {
|
||||
nConnectionsMessageReceived(message.content);
|
||||
break;
|
||||
default:
|
||||
//unknown message type
|
||||
// unknown message type
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -259,8 +261,7 @@ double ParallelPeer::latencyStandardDeviation() const {
|
||||
return std::sqrt(latencyVariance);
|
||||
}
|
||||
|
||||
void ParallelPeer::dataMessageReceived(const std::vector<char>& message)
|
||||
{
|
||||
void ParallelPeer::dataMessageReceived(const std::vector<char>& message) {
|
||||
size_t offset = 0;
|
||||
|
||||
// The type of data message received
|
||||
@@ -290,8 +291,10 @@ void ParallelPeer::dataMessageReceived(const std::vector<char>& message)
|
||||
pose.scale = kf._scale;
|
||||
pose.followFocusNodeRotation = kf._followNodeRotation;
|
||||
|
||||
global::navigationHandler->keyframeNavigator().addKeyframe(convertedTimestamp,
|
||||
pose);
|
||||
global::navigationHandler->keyframeNavigator().addKeyframe(
|
||||
convertedTimestamp,
|
||||
pose
|
||||
);
|
||||
break;
|
||||
}
|
||||
case datamessagestructures::Type::TimelineData: {
|
||||
@@ -359,10 +362,9 @@ void ParallelPeer::dataMessageReceived(const std::vector<char>& message)
|
||||
}
|
||||
}
|
||||
|
||||
void ParallelPeer::connectionStatusMessageReceived(const std::vector<char>& message)
|
||||
{
|
||||
void ParallelPeer::connectionStatusMessageReceived(const std::vector<char>& message) {
|
||||
if (message.size() < 2 * sizeof(uint32_t)) {
|
||||
LERROR("Malformed connection status message.");
|
||||
LERROR("Malformed connection status message");
|
||||
return;
|
||||
}
|
||||
size_t pointer = 0;
|
||||
@@ -376,7 +378,7 @@ void ParallelPeer::connectionStatusMessageReceived(const std::vector<char>& mess
|
||||
pointer += sizeof(uint32_t);
|
||||
|
||||
if (hostNameSize > message.size() - pointer) {
|
||||
LERROR("Malformed connection status message.");
|
||||
LERROR("Malformed connection status message");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -387,7 +389,7 @@ void ParallelPeer::connectionStatusMessageReceived(const std::vector<char>& mess
|
||||
pointer += hostNameSize;
|
||||
|
||||
if (status > ParallelConnection::Status::Host) {
|
||||
LERROR("Invalid status.");
|
||||
LERROR("Invalid status");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -410,7 +412,7 @@ void ParallelPeer::connectionStatusMessageReceived(const std::vector<char>& mess
|
||||
void ParallelPeer::nConnectionsMessageReceived(const std::vector<char>& message)
|
||||
{
|
||||
if (message.size() < sizeof(uint32_t)) {
|
||||
LERROR("Malformed host info message.");
|
||||
LERROR("Malformed host info message");
|
||||
return;
|
||||
}
|
||||
const uint32_t nConnections = *(reinterpret_cast<const uint32_t*>(&message[0]));
|
||||
@@ -532,9 +534,54 @@ void ParallelPeer::preSynchronization() {
|
||||
|
||||
void ParallelPeer::setStatus(ParallelConnection::Status status) {
|
||||
if (_status != status) {
|
||||
ParallelConnection::Status prevStatus = _status;
|
||||
_status = status;
|
||||
_timeJumped = true;
|
||||
_connectionEvent->publish("statusChanged");
|
||||
|
||||
|
||||
EventEngine* ee = global::eventEngine;
|
||||
const bool isConnected =
|
||||
status == ParallelConnection::Status::ClientWithoutHost ||
|
||||
status == ParallelConnection::Status::ClientWithHost ||
|
||||
status == ParallelConnection::Status::Host;
|
||||
const bool wasConnected =
|
||||
prevStatus == ParallelConnection::Status::ClientWithoutHost ||
|
||||
prevStatus == ParallelConnection::Status::ClientWithHost ||
|
||||
prevStatus == ParallelConnection::Status::Host;
|
||||
const bool isDisconnected = status == ParallelConnection::Status::Disconnected;
|
||||
const bool wasDisconnected =
|
||||
prevStatus == ParallelConnection::Status::Disconnected;
|
||||
const bool isHost = status == ParallelConnection::Status::Host;
|
||||
const bool wasHost = prevStatus == ParallelConnection::Status::Host;
|
||||
const bool isClient =
|
||||
status == ParallelConnection::Status::ClientWithoutHost ||
|
||||
status == ParallelConnection::Status::ClientWithHost;
|
||||
const bool wasClient =
|
||||
prevStatus == ParallelConnection::Status::ClientWithoutHost ||
|
||||
prevStatus == ParallelConnection::Status::ClientWithHost;
|
||||
|
||||
|
||||
if (isDisconnected && wasConnected) {
|
||||
ee->publishEvent<events::EventParallelConnection>(
|
||||
events::EventParallelConnection::State::Lost
|
||||
);
|
||||
}
|
||||
if (isConnected && wasDisconnected) {
|
||||
ee->publishEvent<events::EventParallelConnection>(
|
||||
events::EventParallelConnection::State::Established
|
||||
);
|
||||
}
|
||||
if (isHost && (wasClient || wasDisconnected)) {
|
||||
ee->publishEvent<events::EventParallelConnection>(
|
||||
events::EventParallelConnection::State::HostshipGained
|
||||
);
|
||||
}
|
||||
if ((isClient || isDisconnected) && wasHost) {
|
||||
ee->publishEvent<events::EventParallelConnection>(
|
||||
events::EventParallelConnection::State::HostshipLost
|
||||
);
|
||||
}
|
||||
}
|
||||
if (isHost()) {
|
||||
global::timeManager->addTimeJumpCallback([this]() {
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
|
||||
#include <openspace/properties/propertyowner.h>
|
||||
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/events/event.h>
|
||||
#include <openspace/events/eventengine.h>
|
||||
#include <openspace/properties/property.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/util/json_helper.h>
|
||||
|
||||
@@ -458,7 +458,7 @@ std::pair<std::vector<Vertex>, std::vector<GLushort>> createSphere(int nSegments
|
||||
// 0 -> PI
|
||||
// azimuth angle (east to west)
|
||||
const float theta = fi * glm::pi<float>() / nSegments;
|
||||
|
||||
|
||||
// 0 -> 2*PI
|
||||
const float phi = fj * glm::pi<float>() * 2.f / nSegments;
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include <openspace/engine/globalscallbacks.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/events/event.h>
|
||||
#include <openspace/events/eventengine.h>
|
||||
#include <openspace/navigation/navigationhandler.h>
|
||||
#include <openspace/navigation/orbitalnavigator.h>
|
||||
#include <openspace/mission/missionmanager.h>
|
||||
@@ -258,7 +260,7 @@ namespace {
|
||||
"Enabled Font Color",
|
||||
"The font color used for enabled options."
|
||||
};
|
||||
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo DisabledFontColorInfo = {
|
||||
"DisabledFontColor",
|
||||
"Disabled Font Color",
|
||||
@@ -397,7 +399,7 @@ RenderEngine::RenderEngine()
|
||||
|
||||
_enabledFontColor.setViewOption(openspace::properties::Property::ViewOptions::Color);
|
||||
addProperty(_enabledFontColor);
|
||||
|
||||
|
||||
_disabledFontColor.setViewOption(openspace::properties::Property::ViewOptions::Color);
|
||||
addProperty(_disabledFontColor);
|
||||
}
|
||||
@@ -1105,8 +1107,11 @@ void RenderEngine::addScreenSpaceRenderable(std::unique_ptr<ScreenSpaceRenderabl
|
||||
s->initialize();
|
||||
s->initializeGL();
|
||||
|
||||
global::screenSpaceRootPropertyOwner->addPropertySubOwner(s.get());
|
||||
ScreenSpaceRenderable* ssr = s.get();
|
||||
global::screenSpaceRootPropertyOwner->addPropertySubOwner(ssr);
|
||||
global::screenSpaceRenderables->push_back(std::move(s));
|
||||
|
||||
global::eventEngine->publishEvent<events::EventScreenSpaceRenderableAdded>(ssr);
|
||||
}
|
||||
|
||||
void RenderEngine::removeScreenSpaceRenderable(ScreenSpaceRenderable* s) {
|
||||
@@ -1119,9 +1124,10 @@ void RenderEngine::removeScreenSpaceRenderable(ScreenSpaceRenderable* s) {
|
||||
if (it != global::screenSpaceRenderables->end()) {
|
||||
s->deinitialize();
|
||||
global::screenSpaceRootPropertyOwner->removePropertySubOwner(s);
|
||||
|
||||
global::screenSpaceRenderables->erase(it);
|
||||
}
|
||||
|
||||
global::eventEngine->publishEvent<events::EventScreenSpaceRenderableRemoved>(s);
|
||||
}
|
||||
|
||||
void RenderEngine::removeScreenSpaceRenderable(const std::string& identifier) {
|
||||
@@ -1131,8 +1137,7 @@ void RenderEngine::removeScreenSpaceRenderable(const std::string& identifier) {
|
||||
}
|
||||
}
|
||||
|
||||
ScreenSpaceRenderable* RenderEngine::screenSpaceRenderable(
|
||||
const std::string& identifier)
|
||||
ScreenSpaceRenderable* RenderEngine::screenSpaceRenderable(const std::string& identifier)
|
||||
{
|
||||
const auto it = std::find_if(
|
||||
global::screenSpaceRenderables->begin(),
|
||||
|
||||
@@ -258,7 +258,7 @@ namespace {
|
||||
std::optional<float> opacity [[codegen::inrange(0.f, 1.f)]];
|
||||
|
||||
// Defines either a single or multiple tags that apply to this
|
||||
// ScreenSpaceRenderable, thus making it possible to address multiple, separate
|
||||
// ScreenSpaceRenderable, thus making it possible to address multiple, separate
|
||||
// Renderables with a single property change
|
||||
std::optional<std::variant<std::string, std::vector<std::string>>> tag;
|
||||
};
|
||||
|
||||
@@ -598,13 +598,9 @@ void Profile::removeAsset(const std::string& path) {
|
||||
}
|
||||
|
||||
const auto it = std::find(assets.cbegin(), assets.cend(), path);
|
||||
if (it == assets.end()) {
|
||||
throw ghoul::RuntimeError(fmt::format(
|
||||
"Tried to remove non-existing asset '{}'", path
|
||||
));
|
||||
if (it != assets.end()) {
|
||||
assets.erase(it);
|
||||
}
|
||||
|
||||
assets.erase(it);
|
||||
}
|
||||
|
||||
std::string Profile::serialize() const {
|
||||
|
||||
+157
-13
@@ -39,6 +39,7 @@
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/misc.h>
|
||||
#include <ghoul/misc/profiling.h>
|
||||
#include <string>
|
||||
#include <stack>
|
||||
@@ -73,6 +74,9 @@ namespace {
|
||||
}
|
||||
}
|
||||
#endif // TRACY_ENABLE
|
||||
|
||||
template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
||||
template <class... Ts> overloaded(Ts...)->overloaded<Ts...>;
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
@@ -121,6 +125,7 @@ void Scene::registerNode(SceneGraphNode* node) {
|
||||
_nodesByIdentifier[node->identifier()] = node;
|
||||
addPropertySubOwner(node);
|
||||
_dirtyNodeRegistry = true;
|
||||
global::eventEngine->publishEvent<events::EventSceneGraphNodeAdded>(node);
|
||||
}
|
||||
|
||||
void Scene::unregisterNode(SceneGraphNode* node) {
|
||||
@@ -140,6 +145,7 @@ void Scene::unregisterNode(SceneGraphNode* node) {
|
||||
}
|
||||
removePropertySubOwner(node);
|
||||
_dirtyNodeRegistry = true;
|
||||
global::eventEngine->publishEvent<events::EventSceneGraphNodeRemoved>(node);
|
||||
}
|
||||
|
||||
void Scene::markNodeRegistryDirty() {
|
||||
@@ -581,6 +587,10 @@ void Scene::updateInterpolations() {
|
||||
i.prop->interpolateValue(t, i.easingFunction);
|
||||
|
||||
i.isExpired = (t == 1.f);
|
||||
|
||||
if (i.isExpired) {
|
||||
global::eventEngine->publishEvent<events::EventInterpolationFinished>(i.prop);
|
||||
}
|
||||
}
|
||||
|
||||
_propertyInterpolationInfos.erase(
|
||||
@@ -613,10 +623,14 @@ void Scene::setPropertiesFromProfile(const Profile& p) {
|
||||
// Remove group name from start of regex and replace with '*'
|
||||
uriOrRegex = removeGroupNameFromUri(uriOrRegex);
|
||||
}
|
||||
_profilePropertyName = uriOrRegex;
|
||||
ghoul::lua::push(L, uriOrRegex);
|
||||
ghoul::lua::push(L, 0.0);
|
||||
|
||||
std::string workingValue = prop.value;
|
||||
ghoul::trimSurroundingCharacters(workingValue, ' ');
|
||||
// Later functions expect the value to be at the last position on the stack
|
||||
propertyPushValueFromProfileToLuaState(L, prop.value);
|
||||
propertyPushProfileValueToLua(L, workingValue);
|
||||
|
||||
applyRegularExpression(
|
||||
L,
|
||||
@@ -631,21 +645,149 @@ void Scene::setPropertiesFromProfile(const Profile& p) {
|
||||
}
|
||||
}
|
||||
|
||||
void propertyPushValueFromProfileToLuaState(ghoul::lua::LuaState& L,
|
||||
const std::string& value)
|
||||
void Scene::propertyPushProfileValueToLua(ghoul::lua::LuaState& L,
|
||||
const std::string& value)
|
||||
{
|
||||
if (luascriptfunctions::isBoolValue(value)) {
|
||||
ghoul::lua::push(L, (value == "true") ? true : false);
|
||||
_valueIsTable = false;
|
||||
ProfilePropertyLua elem = propertyProcessValue(L, value);
|
||||
if (!_valueIsTable) {
|
||||
std::visit(overloaded{
|
||||
[&L](const bool value) {
|
||||
ghoul::lua::push(L, value);
|
||||
},
|
||||
[&L](const float value) {
|
||||
ghoul::lua::push(L, value);
|
||||
},
|
||||
[&L](const std::string value) {
|
||||
ghoul::lua::push(L, value);
|
||||
},
|
||||
[&L](const ghoul::lua::nil_t nilValue) {
|
||||
ghoul::lua::push(L, nilValue);
|
||||
}
|
||||
}, elem);
|
||||
}
|
||||
else if (luascriptfunctions::isFloatValue(value)) {
|
||||
ghoul::lua::push(L, std::stof(value));
|
||||
}
|
||||
|
||||
ProfilePropertyLua Scene::propertyProcessValue(ghoul::lua::LuaState& L,
|
||||
const std::string& value)
|
||||
{
|
||||
ProfilePropertyLua result;
|
||||
PropertyValueType pType = propertyValueType(value);
|
||||
|
||||
switch (pType) {
|
||||
case PropertyValueType::Boolean:
|
||||
result = (value == "true") ? true : false;
|
||||
break;
|
||||
case PropertyValueType::Float:
|
||||
result = std::stof(value);
|
||||
break;
|
||||
case PropertyValueType::Nil:
|
||||
result = ghoul::lua::nil_t();
|
||||
break;
|
||||
case PropertyValueType::Table:
|
||||
ghoul::trimSurroundingCharacters(const_cast<std::string&>(value), '{');
|
||||
ghoul::trimSurroundingCharacters(const_cast<std::string&>(value), '}');
|
||||
handlePropertyLuaTableEntry(L, value);
|
||||
_valueIsTable = true;
|
||||
break;
|
||||
case PropertyValueType::String:
|
||||
default:
|
||||
ghoul::trimSurroundingCharacters(const_cast<std::string&>(value), '\"');
|
||||
ghoul::trimSurroundingCharacters(const_cast<std::string&>(value), '[');
|
||||
ghoul::trimSurroundingCharacters(const_cast<std::string&>(value), ']');
|
||||
result = value;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Scene::handlePropertyLuaTableEntry(ghoul::lua::LuaState& L, const std::string& value)
|
||||
{
|
||||
PropertyValueType enclosedType;
|
||||
size_t commaPos = value.find(',', 0);
|
||||
if (commaPos != std::string::npos) {
|
||||
enclosedType = propertyValueType(value.substr(0, commaPos));
|
||||
}
|
||||
else {
|
||||
std::string stringRepresentation = value;
|
||||
if (value.compare("nil") != 0) {
|
||||
stringRepresentation = "[[" + stringRepresentation + "]]";
|
||||
enclosedType = propertyValueType(value);
|
||||
}
|
||||
|
||||
switch (enclosedType) {
|
||||
case PropertyValueType::Boolean:
|
||||
LERROR(fmt::format(
|
||||
"A lua table of bool values is not supported. (processing property {})",
|
||||
_profilePropertyName)
|
||||
);
|
||||
break;
|
||||
case PropertyValueType::Float:
|
||||
{
|
||||
std::vector<float> valsF;
|
||||
processPropertyValueTableEntries(L, value, valsF);
|
||||
ghoul::lua::push(L, valsF);
|
||||
}
|
||||
break;
|
||||
case PropertyValueType::String:
|
||||
{
|
||||
std::vector<std::string> valsS;
|
||||
processPropertyValueTableEntries(L, value, valsS);
|
||||
ghoul::lua::push(L, valsS);
|
||||
}
|
||||
break;
|
||||
case PropertyValueType::Table:
|
||||
default:
|
||||
LERROR(fmt::format(
|
||||
"Table-within-a-table values are not supported for profile a "
|
||||
"property (processing property {})", _profilePropertyName
|
||||
));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Scene::processPropertyValueTableEntries(ghoul::lua::LuaState& L,
|
||||
const std::string& value, std::vector<T>& table)
|
||||
{
|
||||
size_t commaPos = 0;
|
||||
size_t prevPos = 0;
|
||||
std::string nextValue;
|
||||
while (commaPos != std::string::npos) {
|
||||
commaPos = value.find(',', prevPos);
|
||||
if (commaPos != std::string::npos) {
|
||||
nextValue = value.substr(prevPos, commaPos - prevPos);
|
||||
prevPos = commaPos + 1;
|
||||
}
|
||||
ghoul::lua::push(L, stringRepresentation);
|
||||
else {
|
||||
nextValue = value.substr(prevPos);
|
||||
}
|
||||
ghoul::trimSurroundingCharacters(nextValue, ' ');
|
||||
ProfilePropertyLua tableElement = propertyProcessValue(L, nextValue);
|
||||
try {
|
||||
table.push_back(std::get<T>(tableElement));
|
||||
}
|
||||
catch (std::bad_variant_access&) {
|
||||
LERROR(fmt::format(
|
||||
"Error attempting to parse profile property setting for "
|
||||
"{} using value = {}", _profilePropertyName, value
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PropertyValueType Scene::propertyValueType(const std::string& value) {
|
||||
if (luascriptfunctions::isBoolValue(value)) {
|
||||
return PropertyValueType::Boolean;
|
||||
}
|
||||
else if (luascriptfunctions::isFloatValue(value)) {
|
||||
return PropertyValueType::Float;
|
||||
}
|
||||
else if (luascriptfunctions::isNilValue(value)) {
|
||||
return PropertyValueType::Nil;
|
||||
}
|
||||
else if (luascriptfunctions::isTableValue(value)) {
|
||||
return PropertyValueType::Table;
|
||||
}
|
||||
else {
|
||||
return PropertyValueType::String;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -769,14 +911,16 @@ scripting::LuaLibrary Scene::luaLibrary() {
|
||||
&luascriptfunctions::worldPosition,
|
||||
{},
|
||||
"string",
|
||||
"Returns the world position of the scene graph node with the given string as identifier"
|
||||
"Returns the world position of the scene graph node with the given "
|
||||
"string as identifier"
|
||||
},
|
||||
{
|
||||
"worldRotation",
|
||||
& luascriptfunctions::worldRotation,
|
||||
{},
|
||||
"string",
|
||||
"Returns the world rotation matrix of the scene graph node with the given string as identifier"
|
||||
"Returns the world rotation matrix of the scene graph node with the "
|
||||
"given string as identifier"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+26
-4
@@ -25,6 +25,8 @@
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/events/event.h>
|
||||
#include <openspace/events/eventengine.h>
|
||||
#include <openspace/navigation/navigationhandler.h>
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <ghoul/lua/luastate.h>
|
||||
@@ -616,7 +618,7 @@ int addSceneGraphNode(lua_State* L) {
|
||||
d.value<std::string>("Identifier") :
|
||||
"Scene";
|
||||
LERRORC(cat, ghoul::to_string(e.result));
|
||||
|
||||
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format("Error loading scene graph node: {}", e.what())
|
||||
@@ -904,7 +906,7 @@ int worldRotation(lua_State* L) {
|
||||
* isBoolValue(const std::string& s):
|
||||
* Used to check if a string is a lua bool type. Returns false if not a valid bool string.
|
||||
*/
|
||||
bool isBoolValue(const std::string& s) {
|
||||
bool isBoolValue(std::string_view s) {
|
||||
return (s == "true" || s == "false");
|
||||
}
|
||||
|
||||
@@ -915,12 +917,32 @@ bool isBoolValue(const std::string& s) {
|
||||
*/
|
||||
bool isFloatValue(const std::string& s) {
|
||||
try {
|
||||
float converted = std::stof(s);
|
||||
return true;
|
||||
float converted = std::numeric_limits<float>::min();
|
||||
converted = std::stof(s);
|
||||
return (converted != std::numeric_limits<float>::min());
|
||||
}
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* isNilValue(const std::string& s):
|
||||
* Used to check if a string is a lua 'nil' value. Returns false if not.
|
||||
*/
|
||||
bool isNilValue(std::string_view s) {
|
||||
return (s == "nil");
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* isTableValue(const std::string& s):
|
||||
* Used to check if a string contains a lua table rather than an individual value.
|
||||
* Returns false if not.
|
||||
*/
|
||||
bool isTableValue(std::string_view s) {
|
||||
return ((s.front() == '{') && (s.back() == '}'));
|
||||
}
|
||||
|
||||
} // namespace openspace::luascriptfunctions
|
||||
|
||||
@@ -111,6 +111,20 @@ namespace {
|
||||
openspace::properties::Property::Visibility::Developer
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ApproachFactorInfo = {
|
||||
"ApproachFactor",
|
||||
"Approach Factor",
|
||||
"This value is a multiplication factor for the interaction sphere that "
|
||||
"determines when the camera is 'approaching' the scene graph node"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ReachFactorInfo = {
|
||||
"ReachFactor",
|
||||
"Reach Factor",
|
||||
"This value is a multiplication factor for the interaction sphere that "
|
||||
"determines when the camera has 'reached' the scene graph node"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo GuiPathInfo = {
|
||||
"GuiPath",
|
||||
"Gui Path",
|
||||
@@ -174,13 +188,10 @@ namespace {
|
||||
// children
|
||||
std::optional<ghoul::Dictionary> renderable [[codegen::reference("renderable")]];
|
||||
|
||||
// A hard-coded bounding sphere to be used for the cases where the Renderable is
|
||||
// not able to provide a reasonable bounding sphere or the calculated bounding
|
||||
// sphere needs to be overwritten for some reason
|
||||
// [[codegen::verbatim(BoundingSphereInfo.description)]]
|
||||
std::optional<double> boundingSphere;
|
||||
|
||||
// A hard-coded radius for limiting the interaction radius, meaning the minimal
|
||||
// distance that the camera can approach this scene graph node
|
||||
// [[codegen::verbatim(InteractionSphereInfo.description)]]
|
||||
std::optional<double> interactionSphere;
|
||||
|
||||
struct Transform {
|
||||
@@ -208,6 +219,36 @@ namespace {
|
||||
// corresponding to a 'Translation', a 'Rotation', and a 'Scale'
|
||||
std::optional<Transform> transform;
|
||||
|
||||
// This value is a multiplication factor for the interaction sphere that
|
||||
// determines when the camera is 'approaching' the scene graph node. If this value
|
||||
// is not specified, a default value of 5 is used instead. This value must be
|
||||
// larger than the reachFactor or unexpected things might happen
|
||||
std::optional<double> approachFactor [[codegen::greaterequal(0.0)]];
|
||||
|
||||
// This value is a multiplication factor for the interaction sphere that
|
||||
// determines when the camera has 'reached' the scene graph node. If this value is
|
||||
// not specified, a default value of 1.25 is used instead. This value must be
|
||||
// smaller than the approachFactor or unexpected things might happen
|
||||
std::optional<double> reachFactor [[codegen::greaterequal(0.0)]];
|
||||
|
||||
// One or multiple actions that are executed whenever the camera is focused on
|
||||
// this scene graph node and if it enters the interaction sphere of the node
|
||||
std::optional<std::variant<std::string, std::vector<std::string>>> onApproach;
|
||||
|
||||
// One or multiple actions that are executed whenever the camera is focused on
|
||||
// this scene graph node and if it transitions from the approach distance to the
|
||||
// reach distance of the node
|
||||
std::optional<std::variant<std::string, std::vector<std::string>>> onReach;
|
||||
|
||||
// One or multiple actions that are executed whenever the camera is focused on
|
||||
// this scene graph node and if it transitions from the reach distance to the
|
||||
// approach distance of the node
|
||||
std::optional<std::variant<std::string, std::vector<std::string>>> onRecede;
|
||||
|
||||
// One or multiple actions that are executed whenever the camera is focused on
|
||||
// this scene graph node and if it exits the interaction sphere of the node
|
||||
std::optional<std::variant<std::string, std::vector<std::string>>> onExit;
|
||||
|
||||
// Specifies the time frame for when this node should be active
|
||||
std::optional<ghoul::Dictionary> timeFrame
|
||||
[[codegen::reference("core_time_frame")]];
|
||||
@@ -287,6 +328,8 @@ ghoul::mm_unique_ptr<SceneGraphNode> SceneGraphNode::createFromDictionary(
|
||||
|
||||
result->_overrideBoundingSphere = p.boundingSphere;
|
||||
result->_overrideInteractionSphere = p.interactionSphere;
|
||||
result->_approachFactor = p.approachFactor.value_or(result->_approachFactor);
|
||||
result->_reachFactor = p.reachFactor.value_or(result->_reachFactor);
|
||||
|
||||
if (p.transform.has_value()) {
|
||||
if (p.transform->translation.has_value()) {
|
||||
@@ -378,6 +421,43 @@ ghoul::mm_unique_ptr<SceneGraphNode> SceneGraphNode::createFromDictionary(
|
||||
));
|
||||
}
|
||||
|
||||
// Extracting the actions from the dictionary
|
||||
if (p.onApproach.has_value()) {
|
||||
if (std::holds_alternative<std::string>(*p.onApproach)) {
|
||||
result->_onApproachAction = { std::get<std::string>(*p.onApproach) };
|
||||
}
|
||||
else {
|
||||
result->_onApproachAction = std::get<std::vector<std::string>>(*p.onApproach);
|
||||
}
|
||||
}
|
||||
|
||||
if (p.onReach.has_value()) {
|
||||
if (std::holds_alternative<std::string>(*p.onReach)) {
|
||||
result->_onReachAction = { std::get<std::string>(*p.onReach) };
|
||||
}
|
||||
else {
|
||||
result->_onReachAction = std::get<std::vector<std::string>>(*p.onReach);
|
||||
}
|
||||
}
|
||||
|
||||
if (p.onRecede.has_value()) {
|
||||
if (std::holds_alternative<std::string>(*p.onRecede)) {
|
||||
result->_onRecedeAction = { std::get<std::string>(*p.onRecede) };
|
||||
}
|
||||
else {
|
||||
result->_onRecedeAction = std::get<std::vector<std::string>>(*p.onRecede);
|
||||
}
|
||||
}
|
||||
|
||||
if (p.onExit.has_value()) {
|
||||
if (std::holds_alternative<std::string>(*p.onExit)) {
|
||||
result->_onExitAction = { std::get<std::string>(*p.onExit) };
|
||||
}
|
||||
else {
|
||||
result->_onExitAction = std::get<std::vector<std::string>>(*p.onExit);
|
||||
}
|
||||
}
|
||||
|
||||
if (p.tag.has_value()) {
|
||||
if (std::holds_alternative<std::string>(*p.tag)) {
|
||||
result->addTag(std::get<std::string>(*p.tag));
|
||||
@@ -425,6 +505,8 @@ SceneGraphNode::SceneGraphNode()
|
||||
}
|
||||
, _boundingSphere(BoundingSphereInfo, -1.0, -1.0, 1e12)
|
||||
, _interactionSphere(InteractionSphereInfo, -1.0, -1.0, 1e12)
|
||||
, _approachFactor(ApproachFactorInfo, 5.0)
|
||||
, _reachFactor(ReachFactorInfo, 1.25)
|
||||
, _computeScreenSpaceValues(ComputeScreenSpaceInfo, false)
|
||||
, _screenSpacePosition(ScreenSpacePositionInfo, glm::ivec2(-1, -1))
|
||||
, _screenVisibility(ScreenVisibilityInfo, false)
|
||||
@@ -463,6 +545,8 @@ SceneGraphNode::SceneGraphNode()
|
||||
// negative values
|
||||
//_interactionSphere.setExponent(10.f);
|
||||
addProperty(_interactionSphere);
|
||||
addProperty(_reachFactor);
|
||||
addProperty(_approachFactor);
|
||||
addProperty(_showDebugSphere);
|
||||
}
|
||||
|
||||
@@ -1066,6 +1150,22 @@ std::vector<SceneGraphNode*> SceneGraphNode::children() const {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& SceneGraphNode::onApproachAction() const {
|
||||
return _onApproachAction;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& SceneGraphNode::onReachAction() const {
|
||||
return _onReachAction;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& SceneGraphNode::onRecedeAction() const {
|
||||
return _onRecedeAction;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& SceneGraphNode::onExitAction() const {
|
||||
return _onExitAction;
|
||||
}
|
||||
|
||||
double SceneGraphNode::boundingSphere() const {
|
||||
if (_overrideBoundingSphere.has_value()) {
|
||||
return glm::compMax(scale() * *_overrideBoundingSphere);
|
||||
@@ -1092,6 +1192,14 @@ double SceneGraphNode::interactionSphere() const {
|
||||
}
|
||||
}
|
||||
|
||||
double SceneGraphNode::reachFactor() const {
|
||||
return _reachFactor;
|
||||
}
|
||||
|
||||
double SceneGraphNode::approachFactor() const {
|
||||
return _approachFactor;
|
||||
}
|
||||
|
||||
const Renderable* SceneGraphNode::renderable() const {
|
||||
return _renderable.get();
|
||||
}
|
||||
|
||||
@@ -70,12 +70,30 @@ std::string SceneLicenseWriter::generateJson() const {
|
||||
constexpr const char* replStr = R"("{}": "{}", )";
|
||||
constexpr const char* replStr2 = R"("{}": "{}")";
|
||||
json << "{";
|
||||
json << fmt::format(replStr, "name", escapedJson(global::profile->meta->name.value()));
|
||||
json << fmt::format(replStr, "version", escapedJson(global::profile->meta->version.value()));
|
||||
json << fmt::format(replStr, "description", escapedJson(global::profile->meta->description.value()));
|
||||
json << fmt::format(replStr, "author", escapedJson(global::profile->meta->author.value()));
|
||||
json << fmt::format(replStr, "url", escapedJson(global::profile->meta->url.value()));
|
||||
json << fmt::format(replStr2, "license", escapedJson(global::profile->meta->license.value()));
|
||||
json << fmt::format(
|
||||
replStr,
|
||||
"name", escapedJson(global::profile->meta->name.value_or(""))
|
||||
);
|
||||
json << fmt::format(
|
||||
replStr,
|
||||
"version", escapedJson(global::profile->meta->version.value_or(""))
|
||||
);
|
||||
json << fmt::format(
|
||||
replStr,
|
||||
"description", escapedJson(global::profile->meta->description.value_or(""))
|
||||
);
|
||||
json << fmt::format(
|
||||
replStr,
|
||||
"author", escapedJson(global::profile->meta->author.value_or(""))
|
||||
);
|
||||
json << fmt::format(
|
||||
replStr,
|
||||
"url", escapedJson(global::profile->meta->url.value_or(""))
|
||||
);
|
||||
json << fmt::format(
|
||||
replStr2,
|
||||
"license", escapedJson(global::profile->meta->license.value_or(""))
|
||||
);
|
||||
json << "}";
|
||||
|
||||
if (++metaCount != metaTotal) {
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace {
|
||||
// executed instead
|
||||
std::string time;
|
||||
|
||||
// The Lua script that will be executed when the specified time is passed
|
||||
// The Lua script that will be executed when the specified time is passed
|
||||
// independent of its direction. This script will be executed before the
|
||||
// specific scripts if both versions are specified
|
||||
std::optional<std::string> script;
|
||||
|
||||
@@ -46,7 +46,7 @@ int loadFile(lua_State* L) {
|
||||
for (size_t i = 1; i <= scriptsDict.size(); ++i) {
|
||||
ghoul::Dictionary d = scriptsDict.value<ghoul::Dictionary>(std::to_string(i));
|
||||
|
||||
scripting::ScriptScheduler::ScheduledScript script =
|
||||
scripting::ScriptScheduler::ScheduledScript script =
|
||||
scripting::ScriptScheduler::ScheduledScript(d);
|
||||
scripts.push_back(script);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,8 @@ namespace {
|
||||
{
|
||||
throw ghoul::lua::LuaRuntimeException(fmt::format(
|
||||
"Ra or Dec '{}' format is incorrect. Correct format is: Ra 'XhYmZs', "
|
||||
"and Dec 'XdYmZs'", str));
|
||||
"and Dec 'XdYmZs'", str
|
||||
));
|
||||
}
|
||||
|
||||
// Construct the number strings
|
||||
@@ -66,7 +67,8 @@ namespace {
|
||||
if (std::floor(temp) != temp) {
|
||||
throw ghoul::lua::LuaRuntimeException(fmt::format(
|
||||
"Ra or Dec '{}' format is incorrect. Correct format is: Ra 'XhYmZs', "
|
||||
"and Dec 'XdYmZs', where X must be an integer", str));
|
||||
"and Dec 'XdYmZs', where X must be an integer", str
|
||||
));
|
||||
}
|
||||
hoursOrDegrees = std::stoi(sHoursOrDegrees);
|
||||
|
||||
@@ -75,83 +77,90 @@ namespace {
|
||||
if (std::floor(temp) != temp) {
|
||||
throw ghoul::lua::LuaRuntimeException(fmt::format(
|
||||
"Ra or Dec '{}' format is incorrect. Correct format is: Ra 'XhYmZs', "
|
||||
"and Dec 'XdYmZs', where Y must be an integer", str));
|
||||
"and Dec 'XdYmZs', where Y must be an integer", str
|
||||
));
|
||||
}
|
||||
minutes = std::stoi(sMinutes);
|
||||
|
||||
// Seconds is a double
|
||||
seconds = std::stod(sSeconds);
|
||||
} catch (const std::invalid_argument& ia) {
|
||||
}
|
||||
catch (const std::invalid_argument&) {
|
||||
throw ghoul::lua::LuaRuntimeException(fmt::format(
|
||||
"Ra or Dec '{}' format is incorrect. Correct format is: Ra 'XhYmZs', "
|
||||
"and Dec 'XdYmZs'", str));
|
||||
"and Dec 'XdYmZs'", str
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void parseRa(const std::string& ra, int& hours, int& minutes, double& seconds) {
|
||||
if (ra.find('d') != std::string::npos) {
|
||||
throw ghoul::lua::LuaRuntimeException(fmt::format(
|
||||
"Ra '{}' format is incorrect. Correct format is: 'XhYmZs'", ra));
|
||||
"Ra '{}' format is incorrect. Correct format is: 'XhYmZs'", ra
|
||||
));
|
||||
}
|
||||
parseString(ra, hours, minutes, seconds);
|
||||
}
|
||||
|
||||
void parseDec(const std::string& dec, int& degrees, int& minutes,
|
||||
double& seconds)
|
||||
{
|
||||
void parseDec(const std::string& dec, int& degrees, int& minutes, double& seconds) {
|
||||
if (dec.find('h') != std::string::npos) {
|
||||
throw ghoul::lua::LuaRuntimeException(fmt::format(
|
||||
"Dec '{}' format is incorrect. Correct format is: 'XdYmZs'", dec));
|
||||
"Dec '{}' format is incorrect. Correct format is: 'XdYmZs'", dec
|
||||
));
|
||||
}
|
||||
parseString(dec, degrees, minutes, seconds);
|
||||
}
|
||||
|
||||
bool isRaDecValid(int raH, int raM, double raS, int decD,
|
||||
int decM, double decS)
|
||||
{
|
||||
bool isRaDecValid(int raH, int raM, double raS, int decD, int decM, double decS) {
|
||||
// Ra
|
||||
if (raH < 0.0 || raH >= 24.0) {
|
||||
LWARNING(fmt::format("Right ascension hours '{}' is outside the allowed "
|
||||
"range of 0 to 24 hours (exclusive)", raH)
|
||||
);
|
||||
LWARNING(fmt::format(
|
||||
"Right ascension hours '{}' is outside the allowed range of 0 to 24 "
|
||||
"hours (exclusive)", raH
|
||||
));
|
||||
return false;
|
||||
}
|
||||
if (raM < 0.0 || raM >= 60.0) {
|
||||
LWARNING(fmt::format("Right ascension minutes '{}' is outside the allowed "
|
||||
"range of 0 to 60 minutes (exclusive)", raM)
|
||||
);
|
||||
LWARNING(fmt::format(
|
||||
"Right ascension minutes '{}' is outside the allowed range of 0 to 60 "
|
||||
"minutes (exclusive)", raM
|
||||
));
|
||||
return false;
|
||||
}
|
||||
if (raS < 0.0 || raS >= 60.0) {
|
||||
LWARNING(fmt::format("Right ascension seconds '{}' is outside the allowed "
|
||||
"range of 0 to 60 seconds (exclusive)", raS)
|
||||
);
|
||||
LWARNING(fmt::format(
|
||||
"Right ascension seconds '{}' is outside the allowed "
|
||||
"range of 0 to 60 seconds (exclusive)", raS
|
||||
));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Dec
|
||||
if (decD < -90.0 || decD > 90.0) {
|
||||
LWARNING(fmt::format("Declination degrees '{}' is outside the allowed range "
|
||||
"of -90 to 90 degrees (inclusive)", decD)
|
||||
);
|
||||
"of -90 to 90 degrees (inclusive)", decD
|
||||
));
|
||||
return false;
|
||||
}
|
||||
else if ((decD == -90.0 || decD == 90.0) && (decM != 0 || decS != 0)) {
|
||||
LWARNING("Total declination is outside the allowed range of -90 to 90 "
|
||||
"degrees (inclusive)"
|
||||
LWARNING(
|
||||
"Total declination is outside the allowed range of -90 to 90 degrees "
|
||||
"(inclusive)"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (decM < 0.0 || decM >= 60.0) {
|
||||
LWARNING(fmt::format("Declination minutes '{}' is outside the allowed range "
|
||||
"of 0 to 60 minutes (exclusive)", decM)
|
||||
);
|
||||
LWARNING(fmt::format(
|
||||
"Declination minutes '{}' is outside the allowed range of 0 to 60 "
|
||||
"minutes (exclusive)", decM
|
||||
));
|
||||
return false;
|
||||
}
|
||||
if (decS < 0.0 || decS >= 60.0) {
|
||||
LWARNING(fmt::format("Declination seconds '{}' is outside the allowed range "
|
||||
"of 0 to 60 seconds (exclusive)", decS)
|
||||
);
|
||||
LWARNING(fmt::format(
|
||||
"Declination seconds '{}' is outside the allowed range of 0 to 60 "
|
||||
"seconds (exclusive)", decS
|
||||
));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -191,12 +200,14 @@ glm::dvec3 icrsToGalacticCartesian(double ra, double dec, double distance) {
|
||||
// Dec format 'XdYmZs', where X is a signed integer, Y is a positive integer and Z is a
|
||||
// positive double
|
||||
// Reference:
|
||||
// https://math.stackexchange.com/questions/15323/how-do-i-calculate-the-cartesian-coordinates-of-stars
|
||||
// https://math.stackexchange.com/questions/15323/how-do-i-calculate-the-cartesian-
|
||||
// coordinates-of-stars
|
||||
glm::dvec2 icrsToDecimalDegrees(const std::string& ra, const std::string& dec) {
|
||||
if (ra.size() < 6 || dec.size() < 6) {
|
||||
throw ghoul::lua::LuaRuntimeException(fmt::format(
|
||||
"Ra '{}' or Dec '{}' format is incorrect. Correct format is: Ra 'XhYmZs', "
|
||||
"and Dec 'XdYmZs'", ra, dec));
|
||||
"and Dec 'XdYmZs'", ra, dec
|
||||
));
|
||||
}
|
||||
|
||||
// Parse right ascension
|
||||
@@ -218,9 +229,10 @@ glm::dvec2 icrsToDecimalDegrees(const std::string& ra, const std::string& dec) {
|
||||
);
|
||||
|
||||
if (!isValid) {
|
||||
LWARNING(fmt::format("Ra '{}' or Dec '{}' is outside the allowed range, "
|
||||
"result may be incorrect", ra, dec)
|
||||
);
|
||||
LWARNING(fmt::format(
|
||||
"Ra '{}' or Dec '{}' is outside the allowed range, result may be incorrect",
|
||||
ra, dec
|
||||
));
|
||||
}
|
||||
|
||||
// Convert from hours/degrees, minutes, seconds to decimal degrees
|
||||
@@ -266,7 +278,8 @@ glm::dvec3 galacticCartesianToIcrs(double x, double y, double z) {
|
||||
// Return a pair with two formatted strings from the decimal degrees ra and dec
|
||||
// References:
|
||||
// https://www.rapidtables.com/convert/number/degrees-to-degrees-minutes-seconds.html,
|
||||
// https://math.stackexchange.com/questions/15323/how-do-i-calculate-the-cartesian-coordinates-of-stars
|
||||
// https://math.stackexchange.com/questions/15323/how-do-i-calculate-the-cartesian-
|
||||
// coordinates-of-stars
|
||||
std::pair<std::string, std::string> decimalDegreesToIcrs(double ra, double dec) {
|
||||
// Radians to degrees
|
||||
double raDeg = ra;
|
||||
@@ -274,21 +287,22 @@ std::pair<std::string, std::string> decimalDegreesToIcrs(double ra, double dec)
|
||||
|
||||
// Check input
|
||||
if (raDeg < 0 || raDeg > 360 || decDeg < -90 || decDeg > 90) {
|
||||
LWARNING(fmt::format("Given Ra '{}' or Dec '{}' is outside the allowed range, "
|
||||
"result may be incorrect", ra, dec)
|
||||
);
|
||||
LWARNING(fmt::format(
|
||||
"Ra '{}' or Dec '{}' is outside the allowed range, result may be incorrect",
|
||||
ra, dec
|
||||
));
|
||||
}
|
||||
|
||||
// Calculate Ra
|
||||
int raHours = std::trunc(raDeg) / 15.0;
|
||||
int raHours = static_cast<int>(std::trunc(raDeg) / 15.0);
|
||||
double raMinutesFull = (raDeg - raHours * 15.0) * 60.0 / 15.0;
|
||||
int raMinutes = std::trunc(raMinutesFull);
|
||||
int raMinutes = static_cast<int>(std::trunc(raMinutesFull));
|
||||
double raSeconds = (raMinutesFull - raMinutes) * 60.0;
|
||||
|
||||
// Calculate Dec
|
||||
int decDegrees = std::trunc(decDeg);
|
||||
int decDegrees = static_cast<int>(std::trunc(decDeg));
|
||||
double decMinutesFull = (abs(decDeg) - abs(decDegrees)) * 60.0;
|
||||
int decMinutes = std::trunc(decMinutesFull);
|
||||
int decMinutes = static_cast<int>(std::trunc(decMinutesFull));
|
||||
double decSeconds = (decMinutesFull - decMinutes) * 60.0;
|
||||
|
||||
// Construct strings
|
||||
@@ -311,9 +325,10 @@ std::pair<std::string, std::string> decimalDegreesToIcrs(double ra, double dec)
|
||||
);
|
||||
|
||||
if (!isValid) {
|
||||
LWARNING(fmt::format("Resulting Ra '{}' or Dec '{}' is outside the allowed range, "
|
||||
"result may be incorrect", result.first, result.second)
|
||||
);
|
||||
LWARNING(fmt::format(
|
||||
"Resulting Ra '{}' or Dec '{}' is outside the allowed range, result may be "
|
||||
"incorrect", result.first, result.second
|
||||
));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+4
-4
@@ -93,9 +93,9 @@ std::string keyToString(KeyWithModifier keyWithModifier) {
|
||||
std::string modifier;
|
||||
if (keyWithModifier.modifier != KeyModifier::None) {
|
||||
for (const openspace::KeyModifierInfo& kmi : openspace::KeyModifierInfos) {
|
||||
// No need for an extra check for the empty modifier since that is mapped to 0,
|
||||
// meaning that the `hasKeyModifier` will always fail for it since it checks
|
||||
// internally against != 0
|
||||
// No need for an extra check for the empty modifier since that is mapped
|
||||
// to 0, meaning that the `hasKeyModifier` will always fail for it since it
|
||||
// checks internally against != 0
|
||||
|
||||
if (hasKeyModifier(keyWithModifier.modifier, kmi.modifier)) {
|
||||
modifier += fmt::format("{}+", kmi.identifier);
|
||||
@@ -126,7 +126,7 @@ std::string to_string(const openspace::Key& key) {
|
||||
return std::string(ki.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace {
|
||||
struct [[codegen::Dictionary(ResourceSynchronization)]] Parameters {
|
||||
// This key specifies the type of ResourceSyncrhonization that gets created. It
|
||||
// has to be one of the valid ResourceSyncrhonizations that are available for
|
||||
// creation (see the FactoryDocumentation for a list of possible
|
||||
// creation (see the FactoryDocumentation for a list of possible
|
||||
// ResourceSyncrhonizations), which depends on the configration of the application
|
||||
std::string type
|
||||
[[codegen::annotation("A ResourceSynchronization created by a factory")]];
|
||||
|
||||
@@ -1377,20 +1377,22 @@ scripting::LuaLibrary SpiceManager::luaLibrary() {
|
||||
&luascriptfunctions::rotationMatrix,
|
||||
{},
|
||||
"{string, string, string}",
|
||||
"Returns the rotationMatrix for a given body in a frame of reference at a specific"
|
||||
"time. The first agument is the target body, the second is the frame of reference,"
|
||||
" the third is the time. Example: openspace.spice.rotationMatrix('"
|
||||
"INSIGHT_LANDER_CRUISE','MARS', '2018 NOV 26 19:45:34')."
|
||||
"Returns the rotationMatrix for a given body in a frame of reference at "
|
||||
"a specific time. The first agument is the target body, the second is "
|
||||
"the frame of reference, the third is the time. Example: "
|
||||
"openspace.spice.rotationMatrix('INSIGHT_LANDER_CRUISE','MARS',"
|
||||
"'2018 NOV 26 19:45:34')."
|
||||
},
|
||||
{
|
||||
"position",
|
||||
&luascriptfunctions::position,
|
||||
{},
|
||||
"{string, string, string, string}",
|
||||
"Returns the position for a target by an observer in a frame of reference at a specific"
|
||||
"time. The first agument is the target body, the second is the observer body, the third"
|
||||
"is the frame of reference, and the fourth is the time. Example: openspace.spice."
|
||||
"position('INSIGHT','MARS','GALACTIC', '2018 NOV 26 19:45:34')."
|
||||
"Returns the position for a target by an observer in a frame of "
|
||||
"reference at a specific time. The first agument is the target body, the "
|
||||
"second is the observer body, the third is the frame of reference, and "
|
||||
"the fourth is the time. Example: openspace.spice.position('INSIGHT',"
|
||||
"'MARS','GALACTIC', '2018 NOV 26 19:45:34')."
|
||||
},
|
||||
{
|
||||
"getSpiceBodies",
|
||||
|
||||
@@ -58,7 +58,7 @@ int loadKernel(lua_State* L) {
|
||||
*/
|
||||
int unloadKernel(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unloadKernel");
|
||||
std::variant<std::string, unsigned int> argument =
|
||||
std::variant<std::string, unsigned int> argument =
|
||||
ghoul::lua::value<std::variant<std::string, unsigned int>>(L);
|
||||
|
||||
if (std::holds_alternative<std::string>(argument)) {
|
||||
@@ -161,7 +161,7 @@ int rotationMatrix(lua_State* L) {
|
||||
|
||||
/**
|
||||
* position({string, string, string, string}):
|
||||
* Returns the position for a given body relative to another body,
|
||||
* Returns the position for a given body relative to another body,
|
||||
* in a given frame of reference, at a specific time.
|
||||
*/
|
||||
int position(lua_State* L) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user