merge with master

This commit is contained in:
ElonOlsson
2021-10-14 11:07:01 -04:00
104 changed files with 2824 additions and 369 deletions
@@ -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));
+105
View File
@@ -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)
+27
View File
@@ -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)
+68
View File
@@ -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)
+6 -6
View File
@@ -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, {}, {} };
+1
View File
@@ -89,6 +89,7 @@ struct Configuration {
bool isCheckingOpenGLState = false;
bool isLoggingOpenGLCalls = false;
bool isPrintingEvents = false;
float shutdownCountdown = 0.f;
+2
View File
@@ -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;
+395
View File
@@ -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__
+125
View File
@@ -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__
+51
View File
@@ -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
+16 -16
View File
@@ -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
+3 -3
View File
@@ -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__
+2 -1
View File
@@ -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;
+1 -1
View File
@@ -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();
+65 -11
View File
@@ -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__
+15
View File
@@ -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;
+1 -1
View File
@@ -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;
+3 -1
View File
@@ -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);
}
+2 -2
View File
@@ -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
+69
View File
@@ -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;
+5 -4
View File
@@ -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
+6 -1
View File
@@ -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>
+2 -2
View File
@@ -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);
+1 -1
View File
@@ -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)) {
+1 -1
View File
@@ -462,7 +462,7 @@ void ConstructOctreeTask::constructOctreeFromFolder(
}
}
}
std::vector<float> filterValues;
auto writeThreads = std::vector<std::thread>(8);
+1 -1
View File
@@ -193,7 +193,7 @@ void ReadFitsTask::readAllFitsFilesFromFolder(const Task::ProgressCallback&) {
}
}
}
size_t nInputFiles = allInputFiles.size();
LINFO("Files to read: " + std::to_string(nInputFiles));
+1 -1
View File
@@ -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);
+9 -5
View File
@@ -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();
+12 -7
View File
@@ -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();
+29 -5
View File
@@ -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;
+10 -3
View File
@@ -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);
+4 -2
View File
@@ -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"
+3 -3
View File
@@ -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__
+4 -1
View File
@@ -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);
+8 -8
View File
@@ -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();
+9 -9
View File
@@ -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;
+2 -1
View File
@@ -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",
+5 -5
View File
@@ -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;
+11 -11
View File
@@ -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
+1
View File
@@ -222,6 +222,7 @@ LoadingScreen = {
}
CheckOpenGLState = false
LogEachOpenGLCall = false
PrintEvents = false
ShutdownCountdown = 3
ScreenshotUseDate = true
+8
View File
@@ -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
+3 -1
View File
@@ -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());
+5 -5
View File
@@ -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;
}
}
}
+6
View File
@@ -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()) {
+7 -2
View File
@@ -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
View File
@@ -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();
}
+50 -3
View File
@@ -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) {
+595
View File
@@ -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
+133
View File
@@ -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
+49
View File
@@ -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
+9 -2
View File
@@ -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)
);
}
+1 -1
View File
@@ -200,7 +200,7 @@ int actions(lua_State* L) {
action.synchronization == interaction::Action::IsSynchronized::Yes
);
lua_settable(L, -3);
lua_settable(L, -3);
}
+23 -3
View File
@@ -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) {
+117
View File
@@ -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;
}
+1 -1
View File
@@ -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(
+2 -2
View File
@@ -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_))
+23 -7
View File
@@ -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
+9 -4
View File
@@ -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;
+6 -3
View File
@@ -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,
+3 -6
View File
@@ -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()) {
+2 -2
View File
@@ -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) {
+58 -11
View File
@@ -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]() {
+3
View File
@@ -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>
+1 -1
View File
@@ -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;
+11 -6
View File
@@ -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(),
+1 -1
View File
@@ -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;
};
+2 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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
+113 -5
View File
@@ -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();
}
+24 -6
View File
@@ -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) {
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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);
}
+63 -48
View File
@@ -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
View File
@@ -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();
}
+1 -1
View File
@@ -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")]];
+10 -8
View File
@@ -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",
+2 -2
View File
@@ -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