mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-05-06 11:29:55 -05:00
Merge branch 'master' into feature/profileOverScene
This commit is contained in:
@@ -64,11 +64,7 @@ set(SOURCE_FILES
|
||||
src/profile/propertiesdialog.cpp
|
||||
)
|
||||
|
||||
find_package(Qt5 COMPONENTS Widgets REQUIRED)
|
||||
|
||||
set(MOC_FILES "")
|
||||
qt5_wrap_cpp(
|
||||
MOC_FILES
|
||||
set(HEADER_SOURCE
|
||||
include/launcherwindow.h
|
||||
include/profile/actiondialog.h
|
||||
include/profile/additionalscriptsdialog.h
|
||||
@@ -85,13 +81,42 @@ qt5_wrap_cpp(
|
||||
include/profile/propertiesdialog.h
|
||||
)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Widgets REQUIRED)
|
||||
set(MOC_FILES "")
|
||||
set(RESOURCE_FILES "")
|
||||
qt5_add_resources(RESOURCE_FILES resources/resources.qrc)
|
||||
set(LIBRARIES "")
|
||||
|
||||
if (${QT_VERSION_MAJOR} EQUAL 5)
|
||||
find_package(Qt5 COMPONENTS Widgets)
|
||||
qt5_wrap_cpp(
|
||||
MOC_FILES
|
||||
${HEADER_SOURCE}
|
||||
)
|
||||
qt5_add_resources(RESOURCE_FILES resources/resources.qrc)
|
||||
set(LIBRARIES )
|
||||
elseif (${QT_VERSION_MAJOR} EQUAL 6)
|
||||
find_package(Qt6 COMPONENTS Widgets REQUIRED)
|
||||
|
||||
qt6_wrap_cpp(
|
||||
MOC_FILES
|
||||
${HEADER_SOURCE}
|
||||
)
|
||||
qt6_add_resources(RESOURCE_FILES resources/resources.qrc)
|
||||
elseif (NOT DEFINED QT_VERSION_MAJOR)
|
||||
message(FATAL_ERROR "Unable to find Qt version")
|
||||
else ()
|
||||
message(FATAL_ERROR "Unsupported Qt version")
|
||||
endif()
|
||||
|
||||
add_library(openspace-ui-launcher STATIC ${HEADER_FILES} ${SOURCE_FILES} ${MOC_FILES} ${RESOURCE_FILES})
|
||||
set_openspace_compile_settings(openspace-ui-launcher)
|
||||
target_include_directories(openspace-ui-launcher PUBLIC include)
|
||||
target_link_libraries(openspace-ui-launcher PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets openspace-core)
|
||||
target_link_libraries(
|
||||
openspace-ui-launcher
|
||||
PUBLIC
|
||||
openspace-core
|
||||
Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
set(MSVC_WARNINGS
|
||||
|
||||
@@ -38,7 +38,7 @@ class QListWidget;
|
||||
class QPushButton;
|
||||
class QTextEdit;
|
||||
|
||||
class ActionDialog : public QDialog {
|
||||
class ActionDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ActionDialog(QWidget* parent,
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
class QTextEdit;
|
||||
|
||||
class AdditionalScriptsDialog : public QDialog {
|
||||
class AdditionalScriptsDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
class QTextEdit;
|
||||
class QTreeView;
|
||||
|
||||
class AssetsDialog : public QDialog {
|
||||
class AssetsDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "openspace/scene/profile.h"
|
||||
#include <memory>
|
||||
|
||||
class AssetTreeModel : public QAbstractItemModel {
|
||||
class AssetTreeModel final : public QAbstractItemModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
* function (can be multiple times)
|
||||
* \return QVariant data object
|
||||
*/
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
QVariant data(const QModelIndex& index, int role) const final;
|
||||
|
||||
/**
|
||||
* Returns the header data of the tree view
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
* \return QVariant data object in the header
|
||||
*/
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const override;
|
||||
int role = Qt::DisplayRole) const final;
|
||||
|
||||
/**
|
||||
* Returns the index of item in #QModelIndex object form
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
* \return #QModelIndex index of the item at specified position
|
||||
*/
|
||||
QModelIndex index(int row, int column,
|
||||
const QModelIndex& parent = QModelIndex()) const override;
|
||||
const QModelIndex& parent = QModelIndex()) const final;
|
||||
|
||||
/**
|
||||
* Returns the index of the parent of the item specified by input param
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
* \param index of item that is a child of the parent
|
||||
* \return #QModelIndex index of the parent
|
||||
*/
|
||||
QModelIndex parent(const QModelIndex& index) const override;
|
||||
QModelIndex parent(const QModelIndex& index) const final;
|
||||
|
||||
/**
|
||||
* Returns the index of the parent of the item specified by the input params
|
||||
@@ -103,7 +103,7 @@ public:
|
||||
* \param parent #QModelIndex of the parent item
|
||||
* \return number of children/rows of this parent
|
||||
*/
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const final;
|
||||
|
||||
/**
|
||||
* Returns the number of columns of data in each item of the tree
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
* \param parent specified by the #QModelIndex index
|
||||
* \return the number of data columns
|
||||
*/
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const final;
|
||||
|
||||
/**
|
||||
* Return the Qt flags of the item specified by index, which can include
|
||||
@@ -120,7 +120,7 @@ public:
|
||||
* \param index specified by the #QModelIndex index
|
||||
* \return the Qt flags
|
||||
*/
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const final;
|
||||
|
||||
/**
|
||||
* Set data at index \p index
|
||||
@@ -131,7 +131,7 @@ public:
|
||||
* \return true if the data set was successful
|
||||
*/
|
||||
bool setData(const QModelIndex& index, const QVariant& value,
|
||||
int role = Qt::EditRole) override;
|
||||
int role = Qt::EditRole) final;
|
||||
|
||||
/**
|
||||
* Returns a vector of all #Assets selected in the tree view
|
||||
|
||||
@@ -34,7 +34,7 @@ class QLabel;
|
||||
class QLineEdit;
|
||||
class QTabWidget;
|
||||
|
||||
class CameraDialog : public QDialog {
|
||||
class CameraDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -33,7 +33,7 @@ class QListWidget;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
|
||||
class DeltaTimesDialog : public QDialog {
|
||||
class DeltaTimesDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -32,7 +32,7 @@ class QListWidget;
|
||||
class QListWidgetItem;
|
||||
class QPushButton;
|
||||
|
||||
class MarkNodesDialog : public QDialog {
|
||||
class MarkNodesDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
class QLineEdit;
|
||||
class QTextEdit;
|
||||
|
||||
class MetaDialog : public QDialog {
|
||||
class MetaDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -35,7 +35,7 @@ class QLineEdit;
|
||||
class QListWidget;
|
||||
class QPushButton;
|
||||
|
||||
class ModulesDialog : public QDialog {
|
||||
class ModulesDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@ class QLabel;
|
||||
class QLineEdit;
|
||||
class QTextEdit;
|
||||
|
||||
class ProfileEdit : public QDialog {
|
||||
class ProfileEdit final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@ class QLineEdit;
|
||||
class QListWidget;
|
||||
class QPushButton;
|
||||
|
||||
class PropertiesDialog : public QDialog {
|
||||
class PropertiesDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <QDialog>
|
||||
#include <QListWidget>
|
||||
|
||||
class ScriptlogDialog : public QDialog {
|
||||
class ScriptlogDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -34,7 +34,7 @@ class QDateTimeEdit;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
|
||||
class TimeDialog : public QDialog {
|
||||
class TimeDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -65,8 +65,8 @@ ActionDialog::ActionDialog(QWidget* parent,
|
||||
std::vector<openspace::Profile::Keybinding>* keybindings)
|
||||
: QDialog(parent)
|
||||
, _actions(actions)
|
||||
, _keybindings(keybindings)
|
||||
, _actionData(*_actions)
|
||||
, _keybindings(keybindings)
|
||||
, _keybindingsData(*_keybindings)
|
||||
{
|
||||
setWindowTitle("Actions and Keybindings");
|
||||
@@ -512,9 +512,7 @@ void ActionDialog::actionSaved() {
|
||||
|
||||
const auto it = std::find_if(
|
||||
_actionData.begin(), _actionData.end(),
|
||||
[id = newIdentifier](const Profile::Action& action) {
|
||||
return action.identifier == id;
|
||||
}
|
||||
[id = newIdentifier](const Profile::Action& a) { return a.identifier == id; }
|
||||
);
|
||||
if (it != _actionData.end()) {
|
||||
QMessageBox::critical(
|
||||
|
||||
+1
-1
Submodule apps/OpenSpace/ext/sgct updated: 2a3ef78f72...a7b225f605
@@ -960,7 +960,7 @@ void checkCommandLineForSettings(int& argc, char** argv, bool& hasSGCT, bool& ha
|
||||
}
|
||||
|
||||
std::string setWindowConfigPresetForGui(const std::string labelFromCfgFile,
|
||||
const std::string xmlExt, bool haveCliSGCTConfig,
|
||||
bool haveCliSGCTConfig,
|
||||
const std::string& sgctFunctionName)
|
||||
{
|
||||
configuration::Configuration& config = *global::configuration;
|
||||
@@ -1046,8 +1046,9 @@ int main(int argc, char* argv[]) {
|
||||
//
|
||||
// Parse commandline arguments
|
||||
//
|
||||
char* prgName = argv[0];
|
||||
ghoul::cmdparser::CommandlineParser parser(
|
||||
std::string(argv[0]),
|
||||
std::string(prgName),
|
||||
ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes
|
||||
);
|
||||
|
||||
@@ -1159,7 +1160,6 @@ int main(int argc, char* argv[]) {
|
||||
const std::string xmlExt = ".xml";
|
||||
std::string windowCfgPreset = setWindowConfigPresetForGui(
|
||||
labelFromCfgFile,
|
||||
xmlExt,
|
||||
hasSGCTConfig,
|
||||
sgctFunctionName
|
||||
);
|
||||
|
||||
@@ -129,4 +129,4 @@ int main(int argc, char** argv) {
|
||||
LINFO("Server stopped");
|
||||
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local earth = asset.require('scene/solarsystem/planets/earth/earth')
|
||||
local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
|
||||
|
||||
local models = asset.syncedResource({
|
||||
Name = "New Horizons Model",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "newhorizons_model",
|
||||
Version = 2
|
||||
})
|
||||
|
||||
local lat = 40.7306
|
||||
local long = -73.9352
|
||||
|
||||
local Example_GlobeRotation = {
|
||||
Identifier = "Example_GlobeRotation",
|
||||
Parent = earth.Earth.Identifier,
|
||||
Transform = {
|
||||
Translation = {
|
||||
Type = "GlobeTranslation",
|
||||
Globe = earth.Earth.Identifier,
|
||||
Latitude = lat,
|
||||
Longitude = long,
|
||||
Altitude = 6,
|
||||
UseHeightmap = true
|
||||
},
|
||||
Rotation = {
|
||||
Type = "GlobeRotation",
|
||||
Globe = earth.Earth.Identifier,
|
||||
Latitude = lat,
|
||||
Longitude = long
|
||||
-- Can be used to to put flat on leaning surfaces, but also leads to updating
|
||||
-- the rotation every frame
|
||||
--UseHeightmap = true
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
Type = "RenderableModel",
|
||||
Body = "NEW HORIZONS",
|
||||
GeometryFile = models .. "/NewHorizonsCleanModel.obj"
|
||||
},
|
||||
GUI = {
|
||||
Path = "/Example"
|
||||
}
|
||||
}
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { Example_GlobeRotation })
|
||||
@@ -16,8 +16,8 @@ local Example_Fixed_Height = {
|
||||
Translation = {
|
||||
Type = "GlobeTranslation",
|
||||
Globe = earth.Earth.Identifier,
|
||||
Longitude = -74.006,
|
||||
Latitude = 40.7128,
|
||||
Longitude = -74.006,
|
||||
Altitude = 100000.0
|
||||
}
|
||||
},
|
||||
@@ -38,8 +38,8 @@ local Example_Adaptive_Height = {
|
||||
Translation = {
|
||||
Type = "GlobeTranslation",
|
||||
Globe = earth.Earth.Identifier,
|
||||
Longitude = -74.006,
|
||||
Latitude = 40.7128,
|
||||
Longitude = -74.006,
|
||||
UseHeightmap = true
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 "fragment.glsl"
|
||||
|
||||
in vec2 vs_st;
|
||||
in vec3 vs_normalViewSpace;
|
||||
in vec4 vs_positionCameraSpace;
|
||||
in float vs_screenSpaceDepth;
|
||||
in mat3 TBN;
|
||||
|
||||
uniform float ambientIntensity = 0.2;
|
||||
uniform float diffuseIntensity = 1.0;
|
||||
uniform float specularIntensity = 1.0;
|
||||
|
||||
uniform bool performShading = true;
|
||||
uniform bool use_forced_color = false;
|
||||
uniform bool has_texture_diffuse;
|
||||
uniform bool has_texture_normal;
|
||||
uniform bool has_texture_specular;
|
||||
uniform bool has_color_specular;
|
||||
|
||||
uniform bool opacityBlending = false;
|
||||
|
||||
uniform sampler2D texture_diffuse;
|
||||
uniform sampler2D texture_normal;
|
||||
uniform sampler2D texture_specular;
|
||||
|
||||
uniform vec3 color_diffuse;
|
||||
uniform vec3 color_specular;
|
||||
|
||||
uniform int nLightSources;
|
||||
uniform vec3 lightDirectionsViewSpace[8];
|
||||
uniform float lightIntensities[8];
|
||||
|
||||
uniform float opacity = 1.0;
|
||||
|
||||
Fragment getFragment() {
|
||||
Fragment frag;
|
||||
|
||||
if (has_texture_normal) {
|
||||
vec3 normalAlbedo = texture(texture_normal, vs_st).rgb;
|
||||
normalAlbedo = normalize(normalAlbedo * 2.0 - 1.0);
|
||||
frag.color.rgb = normalize(TBN * normalAlbedo);
|
||||
}
|
||||
else {
|
||||
frag.color.rgb = normalize(vs_normalViewSpace);
|
||||
}
|
||||
frag.color.a = 1.0;
|
||||
frag.gPosition = vs_positionCameraSpace;
|
||||
frag.gNormal = vec4(vs_normalViewSpace, 0.0);
|
||||
frag.disableLDR2HDR = true;
|
||||
return frag;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
#include "PowerScaling/powerScaling_vs.hglsl"
|
||||
|
||||
layout(location = 0) in vec4 in_position;
|
||||
layout(location = 1) in vec2 in_st;
|
||||
layout(location = 2) in vec3 in_normal;
|
||||
layout(location = 3) in vec3 in_tangent;
|
||||
|
||||
out vec2 vs_st;
|
||||
out vec3 vs_normalViewSpace;
|
||||
out float vs_screenSpaceDepth;
|
||||
out vec4 vs_positionCameraSpace;
|
||||
out mat3 TBN;
|
||||
|
||||
uniform mat4 modelViewTransform;
|
||||
uniform mat4 projectionTransform;
|
||||
uniform mat4 normalTransform;
|
||||
uniform mat4 meshTransform;
|
||||
uniform mat4 meshNormalTransform;
|
||||
|
||||
void main() {
|
||||
vs_positionCameraSpace = modelViewTransform * (meshTransform * in_position);
|
||||
vec4 positionClipSpace = projectionTransform * vs_positionCameraSpace;
|
||||
vec4 positionScreenSpace = z_normalization(positionClipSpace);
|
||||
|
||||
gl_Position = positionScreenSpace;
|
||||
vs_st = in_st;
|
||||
vs_screenSpaceDepth = positionScreenSpace.w;
|
||||
|
||||
vs_normalViewSpace = normalize(mat3(normalTransform) * (mat3(meshNormalTransform) * in_normal));
|
||||
|
||||
// TBN matrix for normal mapping
|
||||
vec3 T = normalize(mat3(normalTransform) * (mat3(meshNormalTransform) * in_tangent));
|
||||
vec3 N = normalize(mat3(normalTransform) * (mat3(meshNormalTransform) * in_normal));
|
||||
|
||||
// Re-orthogonalize T with respect to N
|
||||
T = normalize(T - dot(T, N) * N);
|
||||
|
||||
// Retrieve perpendicular vector B with cross product of T and N
|
||||
vec3 B = normalize(cross(N, T));
|
||||
|
||||
TBN = mat3(T, B, N);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
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 model = asset.syncedResource({
|
||||
Name = "Animated Box",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "animated_box",
|
||||
Version = 1
|
||||
})
|
||||
|
||||
local model = {
|
||||
Identifier = "modelshader",
|
||||
Parent = transforms.EarthCenter.Identifier,
|
||||
Transform = {
|
||||
Translation = {
|
||||
Type = "StaticTranslation",
|
||||
Position = { 11E7, 0.0, 0.0 }
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
Type = "RenderableModel",
|
||||
GeometryFile = model .. "/BoxAnimated.glb",
|
||||
ModelScale = 3E7,
|
||||
LightSources = {
|
||||
{
|
||||
Type = "SceneGraphLightSource",
|
||||
Identifier = "Sun",
|
||||
Node = sunTransforms.SolarSystemBarycenter.Identifier,
|
||||
Intensity = 1.0
|
||||
}
|
||||
},
|
||||
PerformShading = true,
|
||||
DisableFaceCulling = true,
|
||||
VertexShader = asset.localResource("model_vs.glsl"),
|
||||
FragmentShader = asset.localResource("model_fs.glsl"),
|
||||
},
|
||||
GUI = {
|
||||
Name = "Model Shader",
|
||||
Path = "/Example",
|
||||
Description = "Simple box model with a custom shader",
|
||||
}
|
||||
}
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { model })
|
||||
@@ -50,6 +50,7 @@ local Apollo15 = {
|
||||
Renderable = {
|
||||
Type = "RenderableModel",
|
||||
GeometryFile = models .. "/ApolloCSM.osmodel",
|
||||
ModelScale = 0.0001,
|
||||
LightSources = {
|
||||
{
|
||||
Type = "SceneGraphLightSource",
|
||||
|
||||
@@ -38,11 +38,6 @@ local Apollo8LaunchModel = {
|
||||
End = "1968 DEC 22"
|
||||
},
|
||||
Transform = {
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
-- The scale of the model is in cm; OpenSpace is in m
|
||||
Scale = 0.01
|
||||
},
|
||||
Rotation = {
|
||||
Type = "StaticRotation",
|
||||
Rotation = {0.0, 0.0, -3.1415 / 2}
|
||||
@@ -51,6 +46,7 @@ local Apollo8LaunchModel = {
|
||||
Renderable = {
|
||||
Type = "RenderableModel",
|
||||
GeometryFile = models .. "/ApolloCSM.osmodel",
|
||||
ModelScale = 0.0001,
|
||||
LightSources = {
|
||||
{
|
||||
Type = "SceneGraphLightSource",
|
||||
|
||||
@@ -50,11 +50,6 @@ local Apollo8Model = {
|
||||
End = "1968 DEC 28"
|
||||
},
|
||||
Transform = {
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
-- The scale of the model is in cm; OpenSpace is in m
|
||||
Scale = 0.01
|
||||
},
|
||||
Rotation = {
|
||||
Type = "StaticRotation",
|
||||
Rotation = {0.0, 0.0, -3.1415 / 2}
|
||||
@@ -63,6 +58,7 @@ local Apollo8Model = {
|
||||
Renderable = {
|
||||
Type = "RenderableModel",
|
||||
GeometryFile = models .. "/ApolloCSM.osmodel",
|
||||
ModelScale = 0.0001,
|
||||
LightSources = {
|
||||
{
|
||||
Type = "SceneGraphLightSource",
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
<GDAL_WMS>
|
||||
<Service name="TiledWMS">
|
||||
<ServerUrl>http://198.102.45.23/arcgis/rest/services/worldelevation3d/terrain3d?</ServerUrl>
|
||||
<TiledGroupName>GCS_Elevation</TiledGroupName>
|
||||
<Service name="TMS">
|
||||
<ServerUrl>http://earthlive.maptiles.arcgis.com/arcgis/rest/services/GCS_Elevation3D/ImageServer/tile/${z}/${y}/${x}</ServerUrl>
|
||||
</Service>
|
||||
<Timeout>2</Timeout>
|
||||
<DataWindow>
|
||||
<UpperLeftX>-180</UpperLeftX> <UpperLeftY>90</UpperLeftY>
|
||||
<LowerRightX>180</LowerRightX> <LowerRightY>-90</LowerRightY>
|
||||
<SizeX>16777216</SizeX> <SizeY>8388608</SizeY>
|
||||
<TileLevel>14</TileLevel> <YOrigin>top</YOrigin>
|
||||
</DataWindow>
|
||||
<Projection>EPSG:4326</Projection>
|
||||
<BlockSizeX>512</BlockSizeX> <BlockSizeY>512</BlockSizeY>
|
||||
<BandsCount>1</BandsCount> <DataType>Float32</DataType>
|
||||
<DataValues NoData="0" Min="-11000" Max="8500"/>
|
||||
<MaxConnections>5</MaxConnections>
|
||||
<ZeroBlockHttpCodes>404,400</ZeroBlockHttpCodes>
|
||||
</GDAL_WMS>
|
||||
|
||||
@@ -3,7 +3,7 @@ asset.require('./static_server')
|
||||
local guiCustomization = asset.require('customization/gui')
|
||||
|
||||
-- Select which commit hashes to use for the frontend and backend
|
||||
local frontendHash = "829260614bb95e236d23cb500f6ec0fb2e3bdf51"
|
||||
local frontendHash = "b777c48280801e3b54cf77c1231f949fe6e69ace"
|
||||
local dataProvider = "data.openspaceproject.com/files/webgui"
|
||||
|
||||
local frontend = asset.syncedResource({
|
||||
|
||||
+1
-1
Submodule ext/ghoul updated: bce78a781c...c7f7c61026
@@ -28,6 +28,7 @@
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <ghoul/misc/exception.h>
|
||||
#include <ghoul/misc/stringconversion.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -126,18 +127,18 @@ inline std::string to_string(const openspace::interaction::JoystickAction& value
|
||||
case openspace::interaction::JoystickAction::Press: return "Press";
|
||||
case openspace::interaction::JoystickAction::Repeat: return "Repeat";
|
||||
case openspace::interaction::JoystickAction::Release: return "Release";
|
||||
default: throw MissingCaseException();
|
||||
default: throw MissingCaseException();
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr openspace::interaction::JoystickAction from_string(std::string_view string) {
|
||||
if (string == "Idle") { return openspace::interaction::JoystickAction::Idle; }
|
||||
if (string == "Press") { return openspace::interaction::JoystickAction::Press; }
|
||||
if (string == "Repeat") { return openspace::interaction::JoystickAction::Repeat; }
|
||||
if (string == "Idle") { return openspace::interaction::JoystickAction::Idle; }
|
||||
if (string == "Press") { return openspace::interaction::JoystickAction::Press; }
|
||||
if (string == "Repeat") { return openspace::interaction::JoystickAction::Repeat; }
|
||||
if (string == "Release") { return openspace::interaction::JoystickAction::Release; }
|
||||
|
||||
throw RuntimeError("Unknown action '" + std::string(string) + "'");
|
||||
throw RuntimeError(fmt::format("Unknown action '{}'", string));
|
||||
}
|
||||
|
||||
} // namespace ghoul
|
||||
|
||||
@@ -199,7 +199,8 @@ private:
|
||||
struct IdleBehavior : public properties::PropertyOwner {
|
||||
enum Behavior {
|
||||
Orbit = 0,
|
||||
OrbitAtConstantLat
|
||||
OrbitAtConstantLat,
|
||||
OrbitAroundUp
|
||||
};
|
||||
|
||||
IdleBehavior();
|
||||
@@ -369,20 +370,36 @@ private:
|
||||
glm::dquat& localRotation, glm::dquat& globalRotation);
|
||||
|
||||
/**
|
||||
* IdleBehavior::Behavior::Orbit
|
||||
* 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
|
||||
* \param speedScale A speed scale that controls the speed of the motion
|
||||
*/
|
||||
void orbitAnchor(double deltaTime, glm::dvec3& position,
|
||||
glm::dquat& globalRotation, double speedScale);
|
||||
|
||||
/**
|
||||
* IdleBehavior::Behavior::OrbitAtConstantLat
|
||||
* Orbit the current anchor node, but stay on the current latitude band. Note that
|
||||
* this creates a rolling motion if looking at any of the anchor's poles, 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
|
||||
* \param globalRotation The camera's global rotation. Will be changed by the function
|
||||
* \param speedScale A speed scale that controls the speed of the motion
|
||||
*/
|
||||
void orbitAtConstantLatitude(double deltaTime, glm::dvec3& position,
|
||||
void orbitAroundAxis(const glm::dvec3 axis, double deltaTime, glm::dvec3& position,
|
||||
glm::dquat& globalRotation, double speedScale);
|
||||
};
|
||||
|
||||
|
||||
@@ -57,12 +57,6 @@ public:
|
||||
Waypoint startPoint() const;
|
||||
Waypoint endPoint() const;
|
||||
|
||||
/**
|
||||
* Return the specified duration for the path, in seconds. Note that the time it
|
||||
* takes to actually traverse the path will not exactly match the provided duration
|
||||
*/
|
||||
double duration() const;
|
||||
|
||||
/**
|
||||
* Return the total length of the the curve for the path, in meters
|
||||
*/
|
||||
@@ -128,7 +122,6 @@ private:
|
||||
|
||||
Waypoint _start;
|
||||
Waypoint _end;
|
||||
double _duration; // seconds
|
||||
Type _type;
|
||||
|
||||
std::unique_ptr<PathCurve> _curve;
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
*
|
||||
* \param value The value that is used to set this Property
|
||||
*/
|
||||
virtual void set(std::any value) override;
|
||||
virtual void set(std::any value) final;
|
||||
|
||||
/**
|
||||
* Returns the <code>std::type_info</code> describing the template parameter
|
||||
|
||||
@@ -94,9 +94,9 @@ public:
|
||||
virtual void updateRendererData();
|
||||
|
||||
virtual void raycastersChanged(VolumeRaycaster& raycaster,
|
||||
RaycasterListener::IsAttached attached);
|
||||
RaycasterListener::IsAttached attached) override;
|
||||
virtual void deferredcastersChanged(Deferredcaster& deferredcaster,
|
||||
DeferredcasterListener::IsAttached isAttached);
|
||||
DeferredcasterListener::IsAttached isAttached) override;
|
||||
|
||||
private:
|
||||
using RaycasterProgObjMap = std::map<
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <openspace/properties/scalar/intproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
#include <openspace/properties/vector/vec3property.h>
|
||||
#include <openspace/properties/vector/vec4property.h>
|
||||
#include <openspace/properties/triggerproperty.h>
|
||||
#include <openspace/rendering/framebufferrenderer.h>
|
||||
#include <chrono>
|
||||
@@ -219,6 +220,9 @@ private:
|
||||
} _cameraButtonLocations;
|
||||
|
||||
std::string _versionString;
|
||||
|
||||
properties::Vec4Property _enabledFontColor;
|
||||
properties::Vec4Property _disabledFontColor;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
virtual bool isInitializing() const = 0;
|
||||
};
|
||||
|
||||
class SingleThreadedSceneInitializer : public SceneInitializer {
|
||||
class SingleThreadedSceneInitializer final : public SceneInitializer {
|
||||
public:
|
||||
void initializeNode(SceneGraphNode* node) override;
|
||||
std::vector<SceneGraphNode*> takeInitializedNodes() override;
|
||||
@@ -51,7 +51,7 @@ private:
|
||||
std::vector<SceneGraphNode*> _initializedNodes;
|
||||
};
|
||||
|
||||
class MultiThreadedSceneInitializer : public SceneInitializer {
|
||||
class MultiThreadedSceneInitializer final : public SceneInitializer {
|
||||
public:
|
||||
MultiThreadedSceneInitializer(unsigned int nThreads);
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ set(SOURCE_FILES
|
||||
rendering/renderabletrailorbit.cpp
|
||||
rendering/renderabletrailtrajectory.cpp
|
||||
rendering/screenspacedashboard.cpp
|
||||
rendering/screenspacedashboard_lua.inl
|
||||
rendering/screenspaceframebuffer.cpp
|
||||
rendering/screenspaceimagelocal.cpp
|
||||
rendering/screenspaceimageonline.cpp
|
||||
|
||||
@@ -249,6 +249,14 @@ namespace {
|
||||
|
||||
// [[codegen::verbatim(EnableOpacityBlendingInfo.description)]]
|
||||
std::optional<bool> enableOpacityBlending;
|
||||
|
||||
// The path to the vertex shader program that is used instead of the default
|
||||
// shader.
|
||||
std::optional<std::filesystem::path> vertexShader;
|
||||
|
||||
// The path to the fragment shader program that is used instead of the default
|
||||
// shader.
|
||||
std::optional<std::filesystem::path> fragmentShader;
|
||||
};
|
||||
#include "renderablemodel_codegen.cpp"
|
||||
} // namespace
|
||||
@@ -335,7 +343,7 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary)
|
||||
distanceUnit = DistanceUnit::Kilometer;
|
||||
break;
|
||||
|
||||
// Weired units
|
||||
// Weird units
|
||||
case Parameters::ScaleUnit::Thou:
|
||||
distanceUnit = DistanceUnit::Thou;
|
||||
break;
|
||||
@@ -472,6 +480,13 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary)
|
||||
_disableDepthTest = p.disableDepthTest.value_or(_disableDepthTest);
|
||||
_disableFaceCulling = p.disableFaceCulling.value_or(_disableFaceCulling);
|
||||
|
||||
if (p.vertexShader.has_value()) {
|
||||
_vertexShaderPath = p.vertexShader->string();
|
||||
}
|
||||
if (p.fragmentShader.has_value()) {
|
||||
_fragmentShaderPath = p.fragmentShader->string();
|
||||
}
|
||||
|
||||
if (p.lightSources.has_value()) {
|
||||
std::vector<ghoul::Dictionary> lightsources = *p.lightSources;
|
||||
|
||||
@@ -560,16 +575,33 @@ void RenderableModel::initialize() {
|
||||
void RenderableModel::initializeGL() {
|
||||
ZoneScoped
|
||||
|
||||
std::string program = ProgramName;
|
||||
if (!_vertexShaderPath.empty()) {
|
||||
program += "|vs=" + _vertexShaderPath;
|
||||
}
|
||||
if (!_fragmentShaderPath.empty()) {
|
||||
program += "|fs=" + _fragmentShaderPath;
|
||||
}
|
||||
_program = BaseModule::ProgramObjectManager.request(
|
||||
ProgramName,
|
||||
[]() -> std::unique_ptr<ghoul::opengl::ProgramObject> {
|
||||
return global::renderEngine->buildRenderProgram(
|
||||
ProgramName,
|
||||
absPath("${MODULE_BASE}/shaders/model_vs.glsl"),
|
||||
absPath("${MODULE_BASE}/shaders/model_fs.glsl")
|
||||
);
|
||||
program,
|
||||
[&]() -> std::unique_ptr<ghoul::opengl::ProgramObject> {
|
||||
std::filesystem::path vs =
|
||||
_vertexShaderPath.empty() ?
|
||||
absPath("${MODULE_BASE}/shaders/model_vs.glsl") :
|
||||
_vertexShaderPath;
|
||||
std::filesystem::path fs =
|
||||
_fragmentShaderPath.empty() ?
|
||||
absPath("${MODULE_BASE}/shaders/model_fs.glsl") :
|
||||
_fragmentShaderPath;
|
||||
|
||||
return global::renderEngine->buildRenderProgram(ProgramName, vs, fs);
|
||||
}
|
||||
);
|
||||
// We don't really know what kind of shader the user provides us with, so we can't
|
||||
// make the assumption that we are going to use all uniforms
|
||||
_program->setIgnoreUniformLocationError(
|
||||
ghoul::opengl::ProgramObject::IgnoreError::Yes
|
||||
);
|
||||
|
||||
ghoul::opengl::updateUniformLocations(*_program, _uniformCache, UniformNames);
|
||||
|
||||
@@ -581,8 +613,15 @@ void RenderableModel::deinitializeGL() {
|
||||
_geometry->deinitialize();
|
||||
_geometry.reset();
|
||||
|
||||
std::string program = ProgramName;
|
||||
if (!_vertexShaderPath.empty()) {
|
||||
program += "|vs=" + _vertexShaderPath;
|
||||
}
|
||||
if (!_fragmentShaderPath.empty()) {
|
||||
program += "|fs=" + _fragmentShaderPath;
|
||||
}
|
||||
BaseModule::ProgramObjectManager.release(
|
||||
ProgramName,
|
||||
program,
|
||||
[](ghoul::opengl::ProgramObject* p) {
|
||||
global::renderEngine->removeRenderProgram(p);
|
||||
}
|
||||
|
||||
@@ -101,6 +101,8 @@ private:
|
||||
properties::BoolProperty _enableOpacityBlending;
|
||||
properties::OptionProperty _blendingFuncOption;
|
||||
|
||||
std::string _vertexShaderPath;
|
||||
std::string _fragmentShaderPath;
|
||||
ghoul::opengl::ProgramObject* _program = nullptr;
|
||||
UniformCache(opacity, nLightSources, lightDirectionsViewSpace, lightIntensities,
|
||||
modelViewTransform, normalTransform, projectionTransform,
|
||||
|
||||
@@ -338,7 +338,6 @@ void RenderableTrail::internalRender(bool renderLines, bool renderPoints,
|
||||
_programObject->setUniform(_uniformCache.nVertices, nVertices);
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
glm::ivec2 resolution = global::renderEngine->renderingResolution();
|
||||
GLint viewport[4];
|
||||
global::renderEngine->openglStateCache().viewport(viewport);
|
||||
_programObject->setUniform(
|
||||
|
||||
@@ -54,79 +54,10 @@ namespace {
|
||||
#include "screenspacedashboard_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
#include "screenspacedashboard_lua.inl"
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace luascriptfunctions {
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* addDashboardItemToScreenSpace(string, table):
|
||||
*/
|
||||
int addDashboardItemToScreenSpace(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addDashboardItemToScreenSpace");
|
||||
|
||||
const std::string& name = ghoul::lua::value<std::string>(L, 1);
|
||||
const int type = lua_type(L, 2);
|
||||
if (type != LUA_TTABLE) {
|
||||
return ghoul::lua::luaError(L, "Expected argument of type 'table'");
|
||||
}
|
||||
|
||||
ghoul::Dictionary d;
|
||||
try {
|
||||
ghoul::lua::luaDictionaryFromState(L, d);
|
||||
}
|
||||
catch (const ghoul::lua::LuaFormatException& e) {
|
||||
LERRORC("addDashboardItem", e.what());
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScreenSpaceRenderable* ssr = global::renderEngine->screenSpaceRenderable(name);
|
||||
|
||||
if (!ssr) {
|
||||
return ghoul::lua::luaError(L, "Provided name is not a ScreenSpace item");
|
||||
}
|
||||
|
||||
ScreenSpaceDashboard* dash = dynamic_cast<ScreenSpaceDashboard*>(ssr);
|
||||
if (!dash) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
"Provided name is a ScreenSpace item but not a dashboard"
|
||||
);
|
||||
}
|
||||
|
||||
dash->dashboard().addDashboardItem(DashboardItem::createFromDictionary(d));
|
||||
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* removeDashboardItemsFromScreenSpace(string):
|
||||
*/
|
||||
int removeDashboardItemsFromScreenSpace(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeDashboardItemsFromScreenSpace");
|
||||
|
||||
const std::string& name = ghoul::lua::value<std::string>(L, 1);
|
||||
ScreenSpaceRenderable* ssr = global::renderEngine->screenSpaceRenderable(name);
|
||||
|
||||
if (!ssr) {
|
||||
return ghoul::lua::luaError(L, "Provided name is not a ScreenSpace item");
|
||||
}
|
||||
|
||||
ScreenSpaceDashboard* dash = dynamic_cast<ScreenSpaceDashboard*>(ssr);
|
||||
if (!dash) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
"Provided name is a ScreenSpace item but not a dashboard"
|
||||
);
|
||||
}
|
||||
|
||||
dash->dashboard().clearDashboardItems();
|
||||
return 0;
|
||||
}
|
||||
} // namespace luascriptfunctions
|
||||
|
||||
documentation::Documentation ScreenSpaceDashboard::Documentation() {
|
||||
return codegen::doc<Parameters>("base_screenspace_dashboard");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 {
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* addDashboardItemToScreenSpace(string, table):
|
||||
*/
|
||||
int addDashboardItemToScreenSpace(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addDashboardItemToScreenSpace");
|
||||
auto [name, d] = ghoul::lua::values<std::string, ghoul::Dictionary>(L);
|
||||
|
||||
ScreenSpaceRenderable* ssr = global::renderEngine->screenSpaceRenderable(name);
|
||||
if (!ssr) {
|
||||
return ghoul::lua::luaError(L, "Provided name is not a ScreenSpace item");
|
||||
}
|
||||
|
||||
ScreenSpaceDashboard* dash = dynamic_cast<ScreenSpaceDashboard*>(ssr);
|
||||
if (!dash) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
"Provided name is a ScreenSpace item but not a dashboard"
|
||||
);
|
||||
}
|
||||
|
||||
dash->dashboard().addDashboardItem(DashboardItem::createFromDictionary(d));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* removeDashboardItemsFromScreenSpace(string):
|
||||
*/
|
||||
int removeDashboardItemsFromScreenSpace(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeDashboardItemsFromScreenSpace");
|
||||
const std::string name = ghoul::lua::value<std::string>(L);
|
||||
|
||||
ScreenSpaceRenderable* ssr = global::renderEngine->screenSpaceRenderable(name);
|
||||
if (!ssr) {
|
||||
return ghoul::lua::luaError(L, "Provided name is not a ScreenSpace item");
|
||||
}
|
||||
|
||||
ScreenSpaceDashboard* dash = dynamic_cast<ScreenSpaceDashboard*>(ssr);
|
||||
if (!dash) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
"Provided name is a ScreenSpace item but not a dashboard"
|
||||
);
|
||||
}
|
||||
|
||||
dash->dashboard().clearDashboardItems();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace openspace::luascriptfunctions
|
||||
@@ -44,15 +44,15 @@ uniform mat4 meshTransform;
|
||||
uniform mat4 meshNormalTransform;
|
||||
|
||||
void main() {
|
||||
vs_positionCameraSpace = modelViewTransform * (meshTransform * in_position);
|
||||
vec4 positionClipSpace = projectionTransform * vs_positionCameraSpace;
|
||||
vec4 positionScreenSpace = z_normalization(positionClipSpace);
|
||||
vs_positionCameraSpace = modelViewTransform * (meshTransform * in_position);
|
||||
vec4 positionClipSpace = projectionTransform * vs_positionCameraSpace;
|
||||
vec4 positionScreenSpace = z_normalization(positionClipSpace);
|
||||
|
||||
gl_Position = positionScreenSpace;
|
||||
vs_st = in_st;
|
||||
vs_screenSpaceDepth = positionScreenSpace.w;
|
||||
gl_Position = positionScreenSpace;
|
||||
vs_st = in_st;
|
||||
vs_screenSpaceDepth = positionScreenSpace.w;
|
||||
|
||||
vs_normalViewSpace = normalize(mat3(normalTransform) * (mat3(meshNormalTransform) * in_normal));
|
||||
vs_normalViewSpace = normalize(mat3(normalTransform) * (mat3(meshNormalTransform) * in_normal));
|
||||
|
||||
// TBN matrix for normal mapping
|
||||
vec3 T = normalize(mat3(normalTransform) * (mat3(meshNormalTransform) * in_tangent));
|
||||
|
||||
@@ -94,11 +94,10 @@ scripting::LuaLibrary DebuggingModule::luaLibrary() const {
|
||||
"addCartesianAxes",
|
||||
&luascriptfunctions::addCartesianAxes,
|
||||
{},
|
||||
"string, string [,number]",
|
||||
"string, [number]",
|
||||
"Adds a set of Cartesian axes to the scene graph node identified by the "
|
||||
"first string, to illustrate its local coordinate system. The second string "
|
||||
"will be used to set the identifier of the axes. The third (optional) "
|
||||
"argument is a scale value, in meters."
|
||||
"first string, to illustrate its local coordinate system. The second "
|
||||
"(optional) argument is a scale value, in meters."
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -61,11 +61,7 @@ namespace openspace::luascriptfunctions {
|
||||
* Renders the current camera path
|
||||
*/
|
||||
int renderCameraPath(lua_State* L) {
|
||||
int nArguments = ghoul::lua::checkArgumentsAndThrow(
|
||||
L,
|
||||
{ 0, 3 },
|
||||
"lua::renderCameraPath"
|
||||
);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 0, 3 }, "lua::renderCameraPath");
|
||||
|
||||
if (!global::navigationHandler->pathNavigator().hasCurrentPath()) {
|
||||
LWARNINGC("Debugging: PathNavigation", "There is no current path to render");
|
||||
@@ -74,12 +70,13 @@ int renderCameraPath(lua_State* L) {
|
||||
const interaction::Path* currentPath =
|
||||
global::navigationHandler->pathNavigator().currentPath();
|
||||
|
||||
const int nSteps = (nArguments > 0) ? ghoul::lua::value<int>(L, 1) : 100;
|
||||
bool renderDirections = (nArguments > 1) ? ghoul::lua::value<bool>(L, 2) : false;
|
||||
auto [nSteps, renderDirections, directionLineLength] = ghoul::lua::values<
|
||||
std::optional<int>, std::optional<bool>, std::optional<double>
|
||||
>(L);
|
||||
|
||||
constexpr const double defaultLineLength = 6e7;
|
||||
const double directionLineLength =
|
||||
(nArguments > 2) ? ghoul::lua::value<double>(L, 3) : defaultLineLength;
|
||||
nSteps = nSteps.value_or(100);
|
||||
renderDirections = renderDirections.value_or(false);
|
||||
directionLineLength = directionLineLength.value_or(6e7);
|
||||
|
||||
// Parent node. Note that we only render one path at a time, so remove the previously
|
||||
// rendered one, if any
|
||||
@@ -98,7 +95,7 @@ int renderCameraPath(lua_State* L) {
|
||||
|
||||
// Get the poses along the path
|
||||
std::vector<CameraPose> poses;
|
||||
const double du = 1.0 / nSteps;
|
||||
const double du = 1.0 / (*nSteps);
|
||||
const double length = currentPath->pathLength();
|
||||
for (double u = 0.0; u < 1.0; u += du) {
|
||||
const CameraPose p = currentPath->interpolatedPose(u * length);
|
||||
@@ -153,11 +150,12 @@ int renderCameraPath(lua_State* L) {
|
||||
);
|
||||
};
|
||||
|
||||
auto addDirectionLine = [addPoint, addLineBetweenPoints, directionLineLength]
|
||||
(const std::string& pointId, const CameraPose& p)
|
||||
auto addDirectionLine = [addPoint, addLineBetweenPoints]
|
||||
(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));
|
||||
const glm::dvec3 pointPosition = p.position + directionLineLength * dir;
|
||||
const glm::dvec3 pointPosition = p.position + lineLength * dir;
|
||||
const std::string id = fmt::format("{}_orientation", pointId);
|
||||
|
||||
addPoint(id, pointPosition);
|
||||
@@ -166,20 +164,19 @@ int renderCameraPath(lua_State* L) {
|
||||
|
||||
// Add first point separately so that we can create first line in for loop
|
||||
addPoint(pointIdentifier(0), poses.front().position);
|
||||
if (renderDirections) {
|
||||
addDirectionLine(pointIdentifier(0), poses.front());
|
||||
if (*renderDirections) {
|
||||
addDirectionLine(pointIdentifier(0), poses.front(), *directionLineLength);
|
||||
}
|
||||
|
||||
for (int i = 1; i < poses.size(); i++) {
|
||||
for (int i = 1; i < static_cast<int>(poses.size()); i++) {
|
||||
addPoint(pointIdentifier(i), poses[i].position);
|
||||
addLineBetweenPoints(pointIdentifier(i), pointIdentifier(i - 1), PathColor, 4.f);
|
||||
|
||||
if (renderDirections) {
|
||||
addDirectionLine(pointIdentifier(i), poses[i]);
|
||||
if (*renderDirections) {
|
||||
addDirectionLine(pointIdentifier(i), poses[i], *directionLineLength);
|
||||
}
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -195,7 +192,6 @@ int removeRenderedCameraPath(lua_State* L) {
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -204,11 +200,7 @@ int removeRenderedCameraPath(lua_State* L) {
|
||||
* Renders the control points of the current camera path
|
||||
*/
|
||||
int renderPathControlPoints(lua_State* L) {
|
||||
int nArguments = ghoul::lua::checkArgumentsAndThrow(
|
||||
L,
|
||||
{ 0, 1 },
|
||||
"lua::renderPathControlPoints"
|
||||
);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 0, 1 }, "lua::renderPathControlPoints");
|
||||
|
||||
if (!global::navigationHandler->pathNavigator().hasCurrentPath()) {
|
||||
LWARNINGC(
|
||||
@@ -219,7 +211,8 @@ int renderPathControlPoints(lua_State* L) {
|
||||
const interaction::Path* currentPath =
|
||||
global::navigationHandler->pathNavigator().currentPath();
|
||||
|
||||
const double radius = (nArguments > 0) ? ghoul::lua::value<int>(L, 1) : 2000000;
|
||||
auto [radius] = ghoul::lua::values<std::optional<double>>(L);
|
||||
radius = radius.value_or(2000000.0);
|
||||
|
||||
// Parent node. Note that we only render one set of points at a time,
|
||||
// so remove any previously rendered ones
|
||||
@@ -259,7 +252,7 @@ int renderPathControlPoints(lua_State* L) {
|
||||
"Type = 'RenderableSphere',"
|
||||
"Enabled = true,"
|
||||
"Segments = 30,"
|
||||
"Size = " + std::to_string(radius) + ","
|
||||
"Size = " + std::to_string(*radius) + ","
|
||||
"Texture = " + colorTexturePath + ""
|
||||
"},"
|
||||
"GUI = {"
|
||||
@@ -274,7 +267,6 @@ int renderPathControlPoints(lua_State* L) {
|
||||
);
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -290,7 +282,6 @@ int removePathControlPoints(lua_State* L) {
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -298,37 +289,33 @@ int removePathControlPoints(lua_State* L) {
|
||||
* Add a set of cartesian axes to the specified scene graph node
|
||||
*/
|
||||
int addCartesianAxes(lua_State* L) {
|
||||
int nArgs = ghoul::lua::checkArgumentsAndThrow(L, { 2, 3 }, "lua::addCartesianAxes");
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::addCartesianAxes");
|
||||
|
||||
const std::string& nodeName = ghoul::lua::value<std::string>(L, 1);
|
||||
const std::string& axesIdentifier = ghoul::lua::value<std::string>(L, 2);
|
||||
auto [nodeIdentifier, scale] =
|
||||
ghoul::lua::values<std::string, std::optional<double>>(L);
|
||||
|
||||
SceneGraphNode* n = global::renderEngine->scene()->sceneGraphNode(nodeName);
|
||||
SceneGraphNode* n = global::renderEngine->scene()->sceneGraphNode(nodeIdentifier);
|
||||
if (!n) {
|
||||
return ghoul::lua::luaError(L, "Unknown scene graph node: " + nodeName);
|
||||
return ghoul::lua::luaError(L, "Unknown scene graph node: " + nodeIdentifier);
|
||||
}
|
||||
|
||||
double scale;
|
||||
if (nArgs > 2) {
|
||||
scale = ghoul::lua::value<double>(L, 3);
|
||||
}
|
||||
else {
|
||||
if (!scale.has_value()) {
|
||||
scale = 2.0 * n->boundingSphere();
|
||||
if (n->boundingSphere() < 1E-3) {
|
||||
LWARNING("Using zero bounding sphere for scale of created axes. You might "
|
||||
"have to set the scale manually for them to be visible");
|
||||
scale += 1.0;
|
||||
scale = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string identifier = makeIdentifier(axesIdentifier);
|
||||
const std::string identifier = makeIdentifier(nodeIdentifier + "_AxesXYZ");
|
||||
const std::string& axes = "{"
|
||||
"Identifier = '" + identifier + "',"
|
||||
"Parent = '" + nodeName + "',"
|
||||
"Parent = '" + nodeIdentifier + "',"
|
||||
"Transform = { "
|
||||
"Scale = {"
|
||||
"Type = 'StaticScale',"
|
||||
"Scale = " + std::to_string(scale) + ""
|
||||
"Scale = " + std::to_string(*scale) + ""
|
||||
"}"
|
||||
"},"
|
||||
"Renderable = {"
|
||||
@@ -349,7 +336,6 @@ int addCartesianAxes(lua_State* L) {
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -200,13 +200,13 @@ std::string ExoplanetsModule::exoplanetsDataPath() const {
|
||||
return absPath(
|
||||
fmt::format("{}/{}", _exoplanetsDataFolder.value(), ExoplanetsDataFileName)
|
||||
).string();
|
||||
};
|
||||
}
|
||||
|
||||
std::string ExoplanetsModule::lookUpTablePath() const {
|
||||
return absPath(
|
||||
fmt::format("{}/{}", _exoplanetsDataFolder, LookupTableFileName)
|
||||
).string();
|
||||
};
|
||||
}
|
||||
|
||||
std::string ExoplanetsModule::bvColormapPath() const {
|
||||
return _bvColorMapPath;
|
||||
|
||||
@@ -88,43 +88,45 @@ ExoplanetSystem findExoplanetSystemInData(std::string_view starName) {
|
||||
std::string name;
|
||||
std::getline(ss, name, ',');
|
||||
|
||||
if (name.substr(0, name.length() - 2) == starName) {
|
||||
std::string location_s;
|
||||
std::getline(ss, location_s);
|
||||
long location = std::stol(location_s.c_str());
|
||||
if (name.substr(0, name.length() - 2) != starName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data.seekg(location);
|
||||
data.read(reinterpret_cast<char*>(&p), sizeof(ExoplanetDataEntry));
|
||||
std::string location_s;
|
||||
std::getline(ss, location_s);
|
||||
long location = std::stol(location_s.c_str());
|
||||
|
||||
sanitizeNameString(name);
|
||||
data.seekg(location);
|
||||
data.read(reinterpret_cast<char*>(&p), sizeof(ExoplanetDataEntry));
|
||||
|
||||
if (!hasSufficientData(p)) {
|
||||
LWARNING(fmt::format("Insufficient data for exoplanet: '{}'", name));
|
||||
continue;
|
||||
}
|
||||
sanitizeNameString(name);
|
||||
|
||||
system.planetNames.push_back(name);
|
||||
system.planetsData.push_back(p);
|
||||
if (!hasSufficientData(p)) {
|
||||
LWARNING(fmt::format("Insufficient data for exoplanet: '{}'", name));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Star data - Should not vary between planets, but one data entry might
|
||||
// lack data for the host star while another does not. So for every planet,
|
||||
// update star data if needed
|
||||
const glm::vec3 pos{ p.positionX, p.positionY, p.positionZ };
|
||||
if (system.starData.position != pos && isValidPosition(pos)) {
|
||||
system.starData.position = pos;
|
||||
}
|
||||
if (system.starData.radius != p.rStar && !std::isnan(p.rStar)) {
|
||||
system.starData.radius = p.rStar;
|
||||
}
|
||||
if (system.starData.bv != p.bmv && !std::isnan(p.bmv)) {
|
||||
system.starData.bv = p.bmv;
|
||||
}
|
||||
if (system.starData.teff != p.teff && !std::isnan(p.teff)) {
|
||||
system.starData.teff = p.teff;
|
||||
}
|
||||
if (system.starData.luminosity != p.luminosity && !std::isnan(p.luminosity)) {
|
||||
system.starData.luminosity = p.luminosity;
|
||||
}
|
||||
system.planetNames.push_back(name);
|
||||
system.planetsData.push_back(p);
|
||||
|
||||
// Star data - Should not vary between planets, but one data entry might lack data
|
||||
// for the host star while another does not. So for every planet, update star data
|
||||
// if needed
|
||||
const glm::vec3 pos = glm::vec3(p.positionX, p.positionY, p.positionZ);
|
||||
if (system.starData.position != pos && isValidPosition(pos)) {
|
||||
system.starData.position = pos;
|
||||
}
|
||||
if (system.starData.radius != p.rStar && !std::isnan(p.rStar)) {
|
||||
system.starData.radius = p.rStar;
|
||||
}
|
||||
if (system.starData.bv != p.bmv && !std::isnan(p.bmv)) {
|
||||
system.starData.bv = p.bmv;
|
||||
}
|
||||
if (system.starData.teff != p.teff && !std::isnan(p.teff)) {
|
||||
system.starData.teff = p.teff;
|
||||
}
|
||||
if (system.starData.luminosity != p.luminosity && !std::isnan(p.luminosity)) {
|
||||
system.starData.luminosity = p.luminosity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,50 +557,40 @@ 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 =
|
||||
ghoul::lua::value<std::variant<std::string, ghoul::Dictionary>>(L);
|
||||
|
||||
const int t = lua_type(L, 1);
|
||||
if (t == LUA_TSTRING) {
|
||||
if (std::holds_alternative<std::string>(v)) {
|
||||
// The user provided a single name
|
||||
const std::string& starName = ghoul::lua::value<std::string>(L, 1);
|
||||
std::string starName = std::get<std::string>(v);
|
||||
createExoplanetSystem(starName);
|
||||
}
|
||||
else if (t == LUA_TTABLE) {
|
||||
else {
|
||||
// A list of names was provided
|
||||
ghoul::Dictionary d;
|
||||
ghoul::lua::luaDictionaryFromState(L, d);
|
||||
|
||||
for (size_t i = 1; i <= d.size(); ++i) {
|
||||
if (!d.hasValue<std::string>(std::to_string(i))) {
|
||||
ghoul::Dictionary starNames = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
for (size_t i = 1; i <= starNames.size(); ++i) {
|
||||
if (!starNames.hasValue<std::string>(std::to_string(i))) {
|
||||
return ghoul::lua::luaError(
|
||||
L, fmt::format("List item {} is of invalid type", i)
|
||||
L,
|
||||
fmt::format("List item {} is of invalid type", i)
|
||||
);
|
||||
}
|
||||
const std::string& starName = d.value<std::string>(std::to_string(i));
|
||||
const std::string& starName = starNames.value<std::string>(std::to_string(i));
|
||||
createExoplanetSystem(starName);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
else {
|
||||
return ghoul::lua::luaError(L, "Invalid input");
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int removeExoplanetSystem(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeExoplanetSystem");
|
||||
std::string starName = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const int StringLocation = -1;
|
||||
const std::string starName = luaL_checkstring(L, StringLocation);
|
||||
const std::string starIdentifier = createIdentifier(starName);
|
||||
|
||||
const std::string starIdentifier = createIdentifier(std::move(starName));
|
||||
openspace::global::scriptEngine->queueScript(
|
||||
"openspace.removeSceneGraphNode('" + starIdentifier + "');",
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -656,7 +648,6 @@ std::vector<std::string> hostStarsWithSufficientData() {
|
||||
// For easier read, sort by names and remove duplicates
|
||||
std::sort(names.begin(), names.end());
|
||||
names.erase(std::unique(names.begin(), names.end()), names.end());
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
@@ -664,15 +655,13 @@ int getListOfExoplanets(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfExoplanets");
|
||||
|
||||
std::vector<std::string> names = hostStarsWithSufficientData();
|
||||
|
||||
lua_newtable(L);
|
||||
int number = 1;
|
||||
for (const std::string& s : names) {
|
||||
lua_pushstring(L, s.c_str());
|
||||
ghoul::lua::push(L, s);
|
||||
lua_rawseti(L, -2, number);
|
||||
++number;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -683,16 +672,15 @@ int listAvailableExoplanetSystems(lua_State* L) {
|
||||
|
||||
std::string output;
|
||||
for (auto it = names.begin(); it != names.end(); ++it) {
|
||||
if (it != names.end()) {
|
||||
output += *it + ", ";
|
||||
}
|
||||
output += *it + ", ";
|
||||
}
|
||||
output.pop_back();
|
||||
output.pop_back();
|
||||
|
||||
LINFO(fmt::format(
|
||||
"There is data available for the following {} exoplanet systems: {}",
|
||||
names.size(), output
|
||||
));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ set(HEADER_FILES
|
||||
src/geodeticpatch.h
|
||||
src/globelabelscomponent.h
|
||||
src/globetranslation.h
|
||||
src/globerotation.h
|
||||
src/gpulayergroup.h
|
||||
src/layer.h
|
||||
src/layeradjustment.h
|
||||
@@ -71,6 +72,7 @@ set(SOURCE_FILES
|
||||
src/geodeticpatch.cpp
|
||||
src/globelabelscomponent.cpp
|
||||
src/globetranslation.cpp
|
||||
src/globerotation.cpp
|
||||
src/gpulayergroup.cpp
|
||||
src/layer.cpp
|
||||
src/layeradjustment.cpp
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <modules/globebrowsing/src/geodeticpatch.h>
|
||||
#include <modules/globebrowsing/src/globelabelscomponent.h>
|
||||
#include <modules/globebrowsing/src/globetranslation.h>
|
||||
#include <modules/globebrowsing/src/globerotation.h>
|
||||
#include <modules/globebrowsing/src/layer.h>
|
||||
#include <modules/globebrowsing/src/layeradjustment.h>
|
||||
#include <modules/globebrowsing/src/layermanager.h>
|
||||
@@ -274,6 +275,10 @@ void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary& dict) {
|
||||
ghoul_assert(fTranslation, "Translation factory was not created");
|
||||
fTranslation->registerClass<globebrowsing::GlobeTranslation>("GlobeTranslation");
|
||||
|
||||
auto fRotation = FactoryManager::ref().factory<Rotation>();
|
||||
ghoul_assert(fRotation, "Rotation factory was not created");
|
||||
fRotation->registerClass<globebrowsing::GlobeRotation>("GlobeRotation");
|
||||
|
||||
auto fTileProvider =
|
||||
std::make_unique<ghoul::TemplateFactory<tileprovider::TileProvider>>();
|
||||
ghoul_assert(fTileProvider, "TileProvider factory was not created");
|
||||
|
||||
@@ -47,10 +47,8 @@ int addLayer(lua_State* L) {
|
||||
ZoneScoped
|
||||
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::addLayer");
|
||||
|
||||
// String arguments
|
||||
const std::string& globeName = ghoul::lua::value<std::string>(L, 1);
|
||||
const std::string& layerGroupName = ghoul::lua::value<std::string>(L, 2);
|
||||
auto [globeName, layerGroupName, layerDict] =
|
||||
ghoul::lua::values<std::string, std::string, ghoul::Dictionary>(L);
|
||||
|
||||
// Get the node and make sure it exists
|
||||
SceneGraphNode* n = global::renderEngine->scene()->sceneGraphNode(globeName);
|
||||
@@ -73,23 +71,10 @@ int addLayer(lua_State* L) {
|
||||
}
|
||||
|
||||
// Get the dictionary defining the layer
|
||||
ghoul::Dictionary d;
|
||||
try {
|
||||
ghoul::lua::luaDictionaryFromState(L, d);
|
||||
}
|
||||
catch (const ghoul::lua::LuaFormatException& e) {
|
||||
LERRORC("addLayerFromDictionary", e.what());
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
lua_settop(L, 0);
|
||||
|
||||
Layer* layer = globe->layerManager().addLayer(groupID, d);
|
||||
Layer* layer = globe->layerManager().addLayer(groupID, layerDict);
|
||||
if (layer) {
|
||||
layer->initialize();
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -98,11 +83,8 @@ int addLayer(lua_State* L) {
|
||||
*/
|
||||
int deleteLayer(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::deleteLayer");
|
||||
|
||||
const std::string& globeName = luaL_checkstring(L, 1);
|
||||
const std::string& layerGroupName = luaL_checkstring(L, 2);
|
||||
const std::string& layerName = luaL_checkstring(L, 3);
|
||||
lua_pop(L, 3);
|
||||
auto [globeName, layerGroupName, layerName] =
|
||||
ghoul::lua::values<std::string, std::string, std::string>(L);
|
||||
|
||||
// Get the node and make sure it exists
|
||||
SceneGraphNode* n = global::renderEngine->scene()->sceneGraphNode(globeName);
|
||||
@@ -125,17 +107,12 @@ int deleteLayer(lua_State* L) {
|
||||
}
|
||||
|
||||
globe->layerManager().deleteLayer(groupID, layerName);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getLayers(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::getLayers");
|
||||
|
||||
const std::string& globeIdentifier = ghoul::lua::value<std::string>(L, 1);
|
||||
const std::string& layer = ghoul::lua::value<std::string>(L, 2);
|
||||
lua_pop(L, 2);
|
||||
auto [globeIdentifier, layer] = ghoul::lua::values<std::string, std::string>(L);
|
||||
|
||||
SceneGraphNode* n = sceneGraphNode(globeIdentifier);
|
||||
if (!n) {
|
||||
@@ -168,12 +145,8 @@ int getLayers(lua_State* L) {
|
||||
|
||||
int moveLayer(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::moveLayer");
|
||||
|
||||
const std::string& globeIdentifier = ghoul::lua::value<std::string>(L, 1);
|
||||
const std::string& layer = ghoul::lua::value<std::string>(L, 2);
|
||||
int oldPosition = ghoul::lua::value<int>(L, 3);
|
||||
int newPosition = ghoul::lua::value<int>(L, 4);
|
||||
lua_pop(L, 4);
|
||||
auto [globeIdentifier, layer, oldPosition, newPosition] =
|
||||
ghoul::lua::values<std::string, std::string, int, int>(L);
|
||||
|
||||
if (oldPosition == newPosition) {
|
||||
return 0;
|
||||
@@ -197,22 +170,16 @@ int moveLayer(lua_State* L) {
|
||||
|
||||
globebrowsing::LayerGroup& lg = globe->layerManager().layerGroup(group);
|
||||
lg.moveLayers(oldPosition, newPosition);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int goToChunk(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::goToChunk");
|
||||
auto [identifier, x, y, level] = ghoul::lua::values<std::string, int, int, int>(L);
|
||||
|
||||
const std::string& globeIdentifier = ghoul::lua::value<std::string>(L, 1);
|
||||
const int x = ghoul::lua::value<int>(L, 2);
|
||||
const int y = ghoul::lua::value<int>(L, 3);
|
||||
const int level = ghoul::lua::value<int>(L, 4);
|
||||
lua_pop(L, 4);
|
||||
|
||||
SceneGraphNode* n = sceneGraphNode(globeIdentifier);
|
||||
SceneGraphNode* n = sceneGraphNode(identifier);
|
||||
if (!n) {
|
||||
return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier);
|
||||
return ghoul::lua::luaError(L, "Unknown globe name: " + identifier);
|
||||
}
|
||||
|
||||
const RenderableGlobe* globe = dynamic_cast<const RenderableGlobe*>(n->renderable());
|
||||
@@ -221,22 +188,18 @@ int goToChunk(lua_State* L) {
|
||||
}
|
||||
|
||||
global::moduleEngine->module<GlobeBrowsingModule>()->goToChunk(*globe, x, y, level);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int goToGeo(lua_State* L) {
|
||||
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToGeo");
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToGeo");
|
||||
|
||||
// Check if the user provided a Scene graph node identifier as the first argument.
|
||||
// lua_isstring returns true for both numbers and strings, so better use !lua_isnumber
|
||||
const bool providedGlobeIdentifier = !lua_isnumber(L, 1);
|
||||
const int parameterOffset = providedGlobeIdentifier ? 1 : 0;
|
||||
|
||||
const SceneGraphNode* n;
|
||||
if (providedGlobeIdentifier) {
|
||||
const std::string& globeIdentifier = ghoul::lua::value<std::string>(L, 1);
|
||||
const std::string& globeIdentifier = ghoul::lua::value<std::string>(L);
|
||||
n = sceneGraphNode(globeIdentifier);
|
||||
if (!n) {
|
||||
return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier);
|
||||
@@ -249,8 +212,8 @@ int goToGeo(lua_State* L) {
|
||||
}
|
||||
}
|
||||
|
||||
const double latitude = ghoul::lua::value<double>(L, parameterOffset + 1);
|
||||
const double longitude = ghoul::lua::value<double>(L, parameterOffset + 2);
|
||||
auto [latitude, longitude, altitude] =
|
||||
ghoul::lua::values<double, double, std::optional<double>>(L);
|
||||
|
||||
const RenderableGlobe* globe = dynamic_cast<const RenderableGlobe*>(n->renderable());
|
||||
if (!globe) {
|
||||
@@ -258,32 +221,29 @@ int goToGeo(lua_State* L) {
|
||||
return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe");
|
||||
}
|
||||
else {
|
||||
return ghoul::lua::luaError(L,
|
||||
"Current anchor node is not a RenderableGlobe. "
|
||||
"Either change the anchor to a globe, or specify a globe identifier "
|
||||
"as the first argument"
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
"Current anchor node is not a RenderableGlobe. Either change the anchor "
|
||||
"to a globe, or specify a globe identifier as the first argument"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (nArguments == parameterOffset + 2) {
|
||||
global::moduleEngine->module<GlobeBrowsingModule>()->goToGeo(
|
||||
*globe, latitude, longitude
|
||||
);
|
||||
}
|
||||
else if (nArguments == parameterOffset + 3) {
|
||||
const double altitude = ghoul::lua::value<double>(L, parameterOffset + 3);
|
||||
if (altitude.has_value()) {
|
||||
global::moduleEngine->module<GlobeBrowsingModule>()->goToGeo(
|
||||
*globe,
|
||||
latitude,
|
||||
longitude,
|
||||
altitude
|
||||
*altitude
|
||||
);
|
||||
}
|
||||
else {
|
||||
global::moduleEngine->module<GlobeBrowsingModule>()->goToGeo(
|
||||
*globe,
|
||||
latitude,
|
||||
longitude
|
||||
);
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -297,7 +257,8 @@ int flyToGeo(lua_State* L) {
|
||||
|
||||
const SceneGraphNode* n;
|
||||
if (providedGlobeIdentifier) {
|
||||
const std::string& globeIdentifier = ghoul::lua::value<std::string>(L, 1);
|
||||
const std::string& globeIdentifier =
|
||||
ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::No);
|
||||
n = sceneGraphNode(globeIdentifier);
|
||||
if (!n) {
|
||||
return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier);
|
||||
@@ -324,9 +285,12 @@ int flyToGeo(lua_State* L) {
|
||||
}
|
||||
}
|
||||
|
||||
const double latitude = ghoul::lua::value<double>(L, parameterOffset + 1);
|
||||
const double longitude = ghoul::lua::value<double>(L, parameterOffset + 2);
|
||||
const double altitude = ghoul::lua::value<double>(L, parameterOffset + 3);
|
||||
const double latitude =
|
||||
ghoul::lua::value<double>(L, parameterOffset + 1, ghoul::lua::PopValue::No);
|
||||
const double longitude =
|
||||
ghoul::lua::value<double>(L, parameterOffset + 2, ghoul::lua::PopValue::No);
|
||||
const double altitude =
|
||||
ghoul::lua::value<double>(L, parameterOffset + 3, ghoul::lua::PopValue::No);
|
||||
|
||||
// Compute the relative position based on the input values
|
||||
auto module = global::moduleEngine->module<GlobeBrowsingModule>();
|
||||
@@ -374,7 +338,8 @@ int flyToGeo(lua_State* L) {
|
||||
}
|
||||
|
||||
if (firstIsNumber || nArguments > firstLocation) {
|
||||
double duration = ghoul::lua::value<double>(L, location);
|
||||
double duration =
|
||||
ghoul::lua::value<double>(L, location, ghoul::lua::PopValue::No);
|
||||
constexpr const double Epsilon = 1e-5;
|
||||
if (duration <= Epsilon) {
|
||||
return ghoul::lua::luaError(L, "Duration must be larger than zero");
|
||||
@@ -394,12 +359,8 @@ int flyToGeo(lua_State* L) {
|
||||
|
||||
int getLocalPositionFromGeo(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::getLocalPositionFromGeo");
|
||||
|
||||
const std::string& globeIdentifier = ghoul::lua::value<std::string>(L, 1);
|
||||
const double latitude = ghoul::lua::value<double>(L, 2);
|
||||
const double longitude = ghoul::lua::value<double>(L, 3);
|
||||
const double altitude = ghoul::lua::value<double>(L, 4);
|
||||
lua_pop(L, 4);
|
||||
auto [globeIdentifier, latitude, longitude, altitude] =
|
||||
ghoul::lua::values<std::string, double, double, double>(L);
|
||||
|
||||
SceneGraphNode* n = sceneGraphNode(globeIdentifier);
|
||||
if (!n) {
|
||||
@@ -411,16 +372,8 @@ int getLocalPositionFromGeo(lua_State* L) {
|
||||
}
|
||||
|
||||
GlobeBrowsingModule& mod = *(global::moduleEngine->module<GlobeBrowsingModule>());
|
||||
glm::vec3 pos = mod.cartesianCoordinatesFromGeo(
|
||||
*globe,
|
||||
latitude,
|
||||
longitude,
|
||||
altitude
|
||||
);
|
||||
|
||||
ghoul::lua::push(L, pos.x, pos.y, pos.z);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 3, "Incorrect number of items left on stack");
|
||||
glm::vec3 p = mod.cartesianCoordinatesFromGeo(*globe, latitude, longitude, altitude);
|
||||
ghoul::lua::push(L, p.x, p.y, p.z);
|
||||
return 3;
|
||||
}
|
||||
|
||||
@@ -450,72 +403,48 @@ int getGeoPositionForCamera(lua_State* L) {
|
||||
posHandle.centerToReferenceSurface);
|
||||
|
||||
ghoul::lua::push(L, glm::degrees(geo2.lat), glm::degrees(geo2.lon), altitude);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 3, "Incorrect number of items left on stack");
|
||||
return 3;
|
||||
}
|
||||
|
||||
int loadWMSCapabilities(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::loadWMSCapabilities");
|
||||
|
||||
std::string name = ghoul::lua::value<std::string>(L, 1);
|
||||
std::string globe = ghoul::lua::value<std::string>(L, 2);
|
||||
std::string url = ghoul::lua::value<std::string>(L, 3);
|
||||
auto [name, globe, url] =
|
||||
ghoul::lua::values<std::string, std::string, std::string>(L);
|
||||
|
||||
global::moduleEngine->module<GlobeBrowsingModule>()->loadWMSCapabilities(
|
||||
std::move(name),
|
||||
std::move(globe),
|
||||
std::move(url)
|
||||
);
|
||||
|
||||
lua_pop(L, 3);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int removeWMSServer(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeWMSServer");
|
||||
|
||||
const std::string& name = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
const std::string name = ghoul::lua::value<std::string>(L);
|
||||
|
||||
global::moduleEngine->module<GlobeBrowsingModule>()->removeWMSServer(name);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int capabilities(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::capabilities");
|
||||
const std::string name = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& name = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
GlobeBrowsingModule::Capabilities cap =
|
||||
global::moduleEngine->module<GlobeBrowsingModule>()->capabilities(name);
|
||||
|
||||
lua_newtable(L);
|
||||
for (unsigned long i = 0; i < cap.size(); ++i) {
|
||||
for (size_t i = 0; i < cap.size(); ++i) {
|
||||
const GlobeBrowsingModule::Layer& l = cap[i];
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
ghoul::lua::push(L, "Name", l.name);
|
||||
lua_settable(L, -3);
|
||||
|
||||
ghoul::lua::push(L, "URL", l.url);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ struct AABB3 {
|
||||
|
||||
|
||||
struct Geodetic2 {
|
||||
double lat = 0.0;
|
||||
double lon = 0.0;
|
||||
double lat = 0.0; // in radians
|
||||
double lon = 0.0; // in radians
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 <modules/globebrowsing/src/globerotation.h>
|
||||
|
||||
#include <modules/globebrowsing/globebrowsingmodule.h>
|
||||
#include <modules/globebrowsing/src/renderableglobe.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
namespace {
|
||||
constexpr openspace::properties::Property::PropertyInfo GlobeInfo = {
|
||||
"Globe",
|
||||
"Attached Globe",
|
||||
"The globe on which the longitude/latitude is specified"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo LatitudeInfo = {
|
||||
"Latitude",
|
||||
"Latitude",
|
||||
"The latitude of the location on the globe's surface. The value can range from "
|
||||
"-90 to 90, with negative values representing the southern hemisphere of the "
|
||||
"globe. The default value is 0.0."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo LongitudeInfo = {
|
||||
"Longitude",
|
||||
"Longitude",
|
||||
"The longitude of the location on the globe's surface. The value can range from "
|
||||
"-180 to 180, with negative values representing the western hemisphere of the "
|
||||
"globe. The default value is 0.0."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo AngleInfo = {
|
||||
"Angle",
|
||||
"Angle",
|
||||
"A rotation angle that can be used to rotate the object around its own y-axis, "
|
||||
"which will be pointing out of the globe's surface."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo UseHeightmapInfo = {
|
||||
"UseHeightmap",
|
||||
"Use Heightmap",
|
||||
"If set to true, the heightmap will be used when computing the surface normal. "
|
||||
"This means that the object will be rotated to lay flat on the surface at the "
|
||||
"given coordinate and follow the shape of the landscape."
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(GlobeRotation)]] Parameters {
|
||||
// [[codegen::verbatim(GlobeInfo.description)]]
|
||||
std::string globe
|
||||
[[codegen::annotation("A valid scene graph node with a RenderableGlobe")]];
|
||||
|
||||
// [[codegen::verbatim(LatitudeInfo.description)]]
|
||||
std::optional<double> latitude;
|
||||
|
||||
// [[codegen::verbatim(LongitudeInfo.description)]]
|
||||
std::optional<double> longitude;
|
||||
|
||||
// [[codegen::verbatim(AngleInfo.description)]]
|
||||
std::optional<double> angle;
|
||||
|
||||
// [[codegen::verbatim(UseHeightmapInfo.description)]]
|
||||
std::optional<bool> useHeightmap;
|
||||
};
|
||||
#include "globerotation_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
|
||||
documentation::Documentation GlobeRotation::Documentation() {
|
||||
return codegen::doc<Parameters>("globebrowsing_rotation_globerotation");
|
||||
}
|
||||
|
||||
GlobeRotation::GlobeRotation(const ghoul::Dictionary& dictionary)
|
||||
: _globe(GlobeInfo)
|
||||
, _latitude(LatitudeInfo, 0.0, -90.0, 90.0)
|
||||
, _longitude(LongitudeInfo, 0.0, -180.0, 180.0)
|
||||
, _angle(AngleInfo, 0.0, 0.0, 360.0)
|
||||
, _useHeightmap(UseHeightmapInfo, false)
|
||||
{
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_globe = p.globe;
|
||||
|
||||
_latitude = p.latitude.value_or(_latitude);
|
||||
_latitude.onChange([this]() { setUpdateVariables(); });
|
||||
addProperty(_latitude);
|
||||
|
||||
_longitude = p.longitude.value_or(_longitude);
|
||||
_longitude.onChange([this]() { setUpdateVariables(); });
|
||||
addProperty(_longitude);
|
||||
|
||||
_useHeightmap = p.useHeightmap.value_or(_useHeightmap);
|
||||
_useHeightmap.onChange([this]() { setUpdateVariables(); });
|
||||
addProperty(_useHeightmap);
|
||||
|
||||
_angle = p.angle.value_or(_angle);
|
||||
_angle.onChange([this]() { setUpdateVariables(); });
|
||||
addProperty(_angle);
|
||||
}
|
||||
|
||||
void GlobeRotation::findGlobe() {
|
||||
SceneGraphNode* n = sceneGraphNode(_globe);
|
||||
if (n->renderable() && dynamic_cast<RenderableGlobe*>(n->renderable())) {
|
||||
_globeNode = dynamic_cast<RenderableGlobe*>(n->renderable());
|
||||
}
|
||||
else {
|
||||
LERRORC(
|
||||
"GlobeRotation",
|
||||
"Could not set attached node as it does not have a RenderableGlobe"
|
||||
);
|
||||
if (_globeNode) {
|
||||
// Reset the globe name to it's previous name
|
||||
_globe = _globeNode->identifier();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GlobeRotation::setUpdateVariables() {
|
||||
_matrixIsDirty = true;
|
||||
requireUpdate();
|
||||
}
|
||||
|
||||
glm::vec3 GlobeRotation::computeSurfacePosition(double latitude, double longitude) const
|
||||
{
|
||||
ghoul_assert(_globeNode, "Globe cannot be nullptr");
|
||||
|
||||
GlobeBrowsingModule* mod = global::moduleEngine->module<GlobeBrowsingModule>();
|
||||
glm::vec3 groundPos = mod->cartesianCoordinatesFromGeo(
|
||||
*_globeNode,
|
||||
latitude,
|
||||
longitude,
|
||||
0.0
|
||||
);
|
||||
|
||||
SurfacePositionHandle h =
|
||||
_globeNode->calculateSurfacePositionHandle(groundPos);
|
||||
|
||||
// Compute position including heightmap
|
||||
return mod->cartesianCoordinatesFromGeo(
|
||||
*_globeNode,
|
||||
latitude,
|
||||
longitude,
|
||||
h.heightToSurface
|
||||
);
|
||||
}
|
||||
|
||||
glm::dmat3 GlobeRotation::matrix(const UpdateData&) const {
|
||||
if (!_globeNode) {
|
||||
// @TODO(abock): The const cast should be removed on a redesign of the rotation
|
||||
// to make the matrix function not constant. Const casting this
|
||||
// away is fine as the factories that create the rotations don't
|
||||
// create them as constant objects
|
||||
const_cast<GlobeRotation*>(this)->findGlobe();
|
||||
_matrixIsDirty = true;
|
||||
}
|
||||
|
||||
if (_useHeightmap) {
|
||||
// If we use the heightmap, we have to compute the height every frame
|
||||
_matrixIsDirty = true;
|
||||
}
|
||||
|
||||
if (!_matrixIsDirty) {
|
||||
return _matrix;
|
||||
}
|
||||
|
||||
// Compute vector that points out of globe surface
|
||||
glm::dvec3 yAxis = glm::dvec3(0.0);
|
||||
if (_useHeightmap) {
|
||||
const double angleDiff = 0.00001; // corresponds to a meter-ish
|
||||
const glm::vec3 posCenter = computeSurfacePosition(_latitude, _longitude);
|
||||
const glm::vec3 pos1 = computeSurfacePosition(_latitude, _longitude + angleDiff);
|
||||
const glm::vec3 pos2 = computeSurfacePosition(_latitude + angleDiff, _longitude);
|
||||
|
||||
const glm::vec3 v1 = pos1 - posCenter;
|
||||
const glm::vec3 v2 = pos2 - posCenter;
|
||||
yAxis = glm::dvec3(glm::cross(v1, v2));
|
||||
}
|
||||
else {
|
||||
float latitudeRad = glm::radians(static_cast<float>(_latitude));
|
||||
float longitudeRad = glm::radians(static_cast<float>(_longitude));
|
||||
yAxis = _globeNode->ellipsoid().geodeticSurfaceNormal(
|
||||
{ latitudeRad, longitudeRad }
|
||||
);
|
||||
}
|
||||
yAxis = glm::normalize(yAxis);
|
||||
|
||||
constexpr const glm::dvec3 n = glm::dvec3(0.0, 0.0, 1.0);
|
||||
glm::dvec3 zAxis = glm::dvec3(
|
||||
zAxis.x = yAxis.y * n.z - yAxis.z * n.y,
|
||||
zAxis.y = yAxis.z * n.x - yAxis.x * n.z,
|
||||
zAxis.z = yAxis.x * n.y - yAxis.y * n.x
|
||||
);
|
||||
zAxis = glm::normalize(zAxis);
|
||||
|
||||
const glm::dvec3 xAxis = glm::normalize(glm::cross(yAxis, zAxis));
|
||||
const glm::dmat3 mat = {
|
||||
xAxis.x, xAxis.y, xAxis.z,
|
||||
yAxis.x, yAxis.y, yAxis.z,
|
||||
zAxis.x, zAxis.y, zAxis.z
|
||||
};
|
||||
|
||||
const glm::dquat q = glm::angleAxis(glm::radians(_angle.value()), yAxis);
|
||||
_matrix = glm::toMat3(q) * mat;
|
||||
_matrixIsDirty = false;
|
||||
return _matrix;
|
||||
}
|
||||
|
||||
} // namespace openspace::globebrowsing
|
||||
@@ -0,0 +1,65 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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_MODULE_GLOBEBROWSING___GLOBEROTATION___H__
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING___GLOBEROTATION___H__
|
||||
|
||||
#include <openspace/scene/rotation.h>
|
||||
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/doubleproperty.h>
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
|
||||
class RenderableGlobe;
|
||||
|
||||
class GlobeRotation : public Rotation {
|
||||
public:
|
||||
GlobeRotation(const ghoul::Dictionary& dictionary);
|
||||
|
||||
glm::dmat3 matrix(const UpdateData& data) const override;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
void findGlobe();
|
||||
void setUpdateVariables();
|
||||
glm::vec3 computeSurfacePosition(double latitude, double longitude) const;
|
||||
|
||||
properties::StringProperty _globe;
|
||||
properties::DoubleProperty _latitude;
|
||||
properties::DoubleProperty _longitude;
|
||||
properties::DoubleProperty _angle;
|
||||
properties::BoolProperty _useHeightmap;
|
||||
|
||||
RenderableGlobe* _globeNode = nullptr;
|
||||
|
||||
mutable bool _matrixIsDirty = true;
|
||||
mutable glm::dmat3 _matrix = glm::dmat3(0.0);
|
||||
};
|
||||
|
||||
} // namespace openspace::globebrowsing
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GLOBEROTATION___H__
|
||||
@@ -42,14 +42,6 @@ namespace {
|
||||
"The globe on which the longitude/latitude is specified"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo LongitudeInfo = {
|
||||
"Longitude",
|
||||
"Longitude",
|
||||
"The longitude of the location on the globe's surface. The value can range from "
|
||||
"-180 to 180, with negative values representing the western hemisphere of the "
|
||||
"globe. The default value is 0.0"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo LatitudeInfo = {
|
||||
"Latitude",
|
||||
"Latitude",
|
||||
@@ -58,6 +50,14 @@ namespace {
|
||||
"globe. The default value is 0.0"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo LongitudeInfo = {
|
||||
"Longitude",
|
||||
"Longitude",
|
||||
"The longitude of the location on the globe's surface. The value can range from "
|
||||
"-180 to 180, with negative values representing the western hemisphere of the "
|
||||
"globe. The default value is 0.0"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo AltitudeInfo = {
|
||||
"Altitude",
|
||||
"Altitude",
|
||||
@@ -80,12 +80,12 @@ namespace {
|
||||
std::string globe
|
||||
[[codegen::annotation("A valid scene graph node with a RenderableGlobe")]];
|
||||
|
||||
// [[codegen::verbatim(LongitudeInfo.description)]]
|
||||
std::optional<double> longitude;
|
||||
|
||||
// [[codegen::verbatim(LatitudeInfo.description)]]
|
||||
std::optional<double> latitude;
|
||||
|
||||
// [[codegen::verbatim(LongitudeInfo.description)]]
|
||||
std::optional<double> longitude;
|
||||
|
||||
// [[codegen::verbatim(AltitudeInfo.description)]]
|
||||
std::optional<double> altitude;
|
||||
|
||||
@@ -103,34 +103,30 @@ documentation::Documentation GlobeTranslation::Documentation() {
|
||||
|
||||
GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary)
|
||||
: _globe(GlobeInfo)
|
||||
, _longitude(LongitudeInfo, 0.0, -180.0, 180.0)
|
||||
, _latitude(LatitudeInfo, 0.0, -90.0, 90.0)
|
||||
, _longitude(LongitudeInfo, 0.0, -180.0, 180.0)
|
||||
, _altitude(AltitudeInfo, 0.0, 0.0, 1e12)
|
||||
, _useHeightmap(UseHeightmapInfo, false)
|
||||
{
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_globe = p.globe;
|
||||
_globe.onChange([this]() {
|
||||
fillAttachedNode();
|
||||
_positionIsDirty = true;
|
||||
});
|
||||
|
||||
_longitude = p.longitude.value_or(_longitude);
|
||||
_longitude.onChange([this]() { _positionIsDirty = true; });
|
||||
addProperty(_longitude);
|
||||
|
||||
_latitude = p.latitude.value_or(_latitude);
|
||||
_latitude.onChange([this]() { _positionIsDirty = true; });
|
||||
_latitude.onChange([this]() { setUpdateVariables(); });
|
||||
addProperty(_latitude);
|
||||
|
||||
_longitude = p.longitude.value_or(_longitude);
|
||||
_longitude.onChange([this]() { setUpdateVariables(); });
|
||||
addProperty(_longitude);
|
||||
|
||||
_altitude = p.altitude.value_or(_altitude);
|
||||
_altitude.setExponent(8.f);
|
||||
_altitude.onChange([this]() { _positionIsDirty = true; });
|
||||
_altitude.onChange([this]() { setUpdateVariables(); });
|
||||
addProperty(_altitude);
|
||||
|
||||
_useHeightmap = p.useHeightmap.value_or(_useHeightmap);
|
||||
_useHeightmap.onChange([this]() { _positionIsDirty = true; });
|
||||
_useHeightmap.onChange([this]() { setUpdateVariables(); });
|
||||
addProperty(_useHeightmap);
|
||||
}
|
||||
|
||||
@@ -151,6 +147,11 @@ void GlobeTranslation::fillAttachedNode() {
|
||||
}
|
||||
}
|
||||
|
||||
void GlobeTranslation::setUpdateVariables() {
|
||||
_positionIsDirty = true;
|
||||
requireUpdate();
|
||||
}
|
||||
|
||||
glm::dvec3 GlobeTranslation::position(const UpdateData&) const {
|
||||
if (!_attachedNode) {
|
||||
// @TODO(abock): The const cast should be removed on a redesign of the translation
|
||||
@@ -170,10 +171,10 @@ glm::dvec3 GlobeTranslation::position(const UpdateData&) const {
|
||||
return _position;
|
||||
}
|
||||
|
||||
GlobeBrowsingModule& mod = *(global::moduleEngine->module<GlobeBrowsingModule>());
|
||||
GlobeBrowsingModule* mod = global::moduleEngine->module<GlobeBrowsingModule>();
|
||||
|
||||
if (_useHeightmap) {
|
||||
glm::vec3 groundPos = mod.cartesianCoordinatesFromGeo(
|
||||
glm::vec3 groundPos = mod->cartesianCoordinatesFromGeo(
|
||||
*_attachedNode,
|
||||
_latitude,
|
||||
_longitude,
|
||||
@@ -183,7 +184,7 @@ glm::dvec3 GlobeTranslation::position(const UpdateData&) const {
|
||||
SurfacePositionHandle h =
|
||||
_attachedNode->calculateSurfacePositionHandle(groundPos);
|
||||
|
||||
_position = mod.cartesianCoordinatesFromGeo(
|
||||
_position = mod->cartesianCoordinatesFromGeo(
|
||||
*_attachedNode,
|
||||
_latitude,
|
||||
_longitude,
|
||||
@@ -192,7 +193,7 @@ glm::dvec3 GlobeTranslation::position(const UpdateData&) const {
|
||||
return _position;
|
||||
}
|
||||
else {
|
||||
_position = mod.cartesianCoordinatesFromGeo(
|
||||
_position = mod->cartesianCoordinatesFromGeo(
|
||||
*_attachedNode,
|
||||
_latitude,
|
||||
_longitude,
|
||||
|
||||
@@ -45,10 +45,11 @@ public:
|
||||
|
||||
private:
|
||||
void fillAttachedNode();
|
||||
void setUpdateVariables();
|
||||
|
||||
properties::StringProperty _globe;
|
||||
properties::DoubleProperty _longitude;
|
||||
properties::DoubleProperty _latitude;
|
||||
properties::DoubleProperty _longitude;
|
||||
properties::DoubleProperty _altitude;
|
||||
properties::BoolProperty _useHeightmap;
|
||||
|
||||
|
||||
@@ -188,7 +188,8 @@ int calculateTileLevelDifference(GDALDataset* dataset, int minimumPixelSize) {
|
||||
}
|
||||
const int sizeLevel0 = maxOverview->GetXSize();
|
||||
const double diff = log2(minimumPixelSize) - log2(sizeLevel0);
|
||||
return static_cast<int>(diff);
|
||||
const double intdiff = diff >= 0 ? ceil(diff) : floor(diff);
|
||||
return static_cast<int>(intdiff);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -370,8 +370,8 @@ void TimeQuantizer::setResolution(const std::string& resolutionString) {
|
||||
}
|
||||
|
||||
void TimeQuantizer::verifyStartTimeRestrictions() {
|
||||
//If monthly time resolution then restrict to 28 days so every month is consistent
|
||||
unsigned int dayUpperLimit;
|
||||
// If monthly time resolution then restrict to 28 days so every month is consistent
|
||||
int dayUpperLimit;
|
||||
std::string helpfulDescription = "the selected month";
|
||||
if (_resolutionUnit == 'M') {
|
||||
dayUpperLimit = 28;
|
||||
@@ -631,7 +631,6 @@ std::vector<std::string> TimeQuantizer::quantized(Time& start, Time& end) {
|
||||
const double startSeconds = s.J2000();
|
||||
const double endSeconds = e.J2000();
|
||||
const double delta = endSeconds - startSeconds;
|
||||
|
||||
ghoul_assert(
|
||||
static_cast<int>(delta) % static_cast<int>(_resolution) == 0,
|
||||
"Quantization error"
|
||||
|
||||
@@ -47,6 +47,7 @@ std::vector<nlohmann::json> ShortcutTopic::shortcutsJson() const {
|
||||
std::vector<nlohmann::json> json;
|
||||
for (const interaction::Action& action : global::actionManager->actions()) {
|
||||
nlohmann::json shortcutJson = {
|
||||
{ "identifier", action.identifier },
|
||||
{ "name", action.name },
|
||||
{ "script", action.command },
|
||||
{ "synchronization", static_cast<bool>(action.synchronization) },
|
||||
@@ -77,11 +78,7 @@ std::vector<nlohmann::json> ShortcutTopic::shortcutsJson() const {
|
||||
{ "super" , hasKeyModifier(k.modifier, KeyModifier::Super) }
|
||||
}
|
||||
},
|
||||
{ "name", action.name },
|
||||
{ "script", action.command },
|
||||
{ "synchronization", static_cast<bool>(action.synchronization) },
|
||||
{ "documentation", action.documentation },
|
||||
{ "guiPath", action.guiPath },
|
||||
{ "action", action.name },
|
||||
};
|
||||
json.push_back(shortcutJson);
|
||||
}
|
||||
|
||||
@@ -134,8 +134,7 @@ RenderableSmallBody::RenderableSmallBody(const ghoul::Dictionary& dictionary)
|
||||
}
|
||||
|
||||
if (dictionary.hasValue<bool>(ContiguousModeInfo.identifier)) {
|
||||
_contiguousMode = static_cast<bool>(
|
||||
dictionary.value<bool>(ContiguousModeInfo.identifier));
|
||||
_contiguousMode = dictionary.value<bool>(ContiguousModeInfo.identifier);
|
||||
}
|
||||
else {
|
||||
_contiguousMode = false;
|
||||
|
||||
@@ -30,48 +30,38 @@ int convertFromRaDec(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::convertFromRaDec");
|
||||
|
||||
glm::dvec2 degrees = glm::dvec2(0.0);
|
||||
if (lua_type(L, 1) == LUA_TSTRING && lua_type(L, 2) == LUA_TSTRING) {
|
||||
std::string ra = ghoul::lua::value<std::string>(L, 1);
|
||||
std::string dec = ghoul::lua::value<std::string>(L, 2);
|
||||
if (ghoul::lua::hasValue<std::string>(L, 1) &&
|
||||
ghoul::lua::hasValue<std::string>(L, 2))
|
||||
{
|
||||
auto [ra, dec] = ghoul::lua::values<std::string, std::string>(L);
|
||||
degrees = icrsToDecimalDegrees(ra, dec);
|
||||
}
|
||||
else if (lua_type(L, 1) == LUA_TNUMBER && lua_type(L, 2) == LUA_TNUMBER) {
|
||||
degrees.x = ghoul::lua::value<double>(L, 1);
|
||||
degrees.y = ghoul::lua::value<double>(L, 2);
|
||||
else if (ghoul::lua::hasValue<double>(L, 1) && ghoul::lua::hasValue<double>(L, 2)) {
|
||||
auto [x, y] = ghoul::lua::values<double, double>(L);
|
||||
degrees.x = x;
|
||||
degrees.y = y;
|
||||
}
|
||||
else {
|
||||
throw ghoul::lua::LuaRuntimeException("lua::convertFromRaDec: Ra and Dec have to "
|
||||
"be of the same type, either String or Number"
|
||||
throw ghoul::lua::LuaRuntimeException(
|
||||
"Ra and Dec have to be of the same type, either String or Number"
|
||||
);
|
||||
}
|
||||
|
||||
double distance = ghoul::lua::value<double>(L, 3);
|
||||
lua_settop(L, 0);
|
||||
|
||||
double distance = ghoul::lua::value<double>(L);
|
||||
glm::dvec3 pos = icrsToGalacticCartesian(degrees.x, degrees.y, distance);
|
||||
ghoul::lua::push(L, pos);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int convertToRaDec(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::convertToRaDec");
|
||||
auto [x, y, z] = ghoul::lua::values<double, double, double>(L);
|
||||
|
||||
double x = ghoul::lua::value<double>(L, 1);
|
||||
double y = ghoul::lua::value<double>(L, 2);
|
||||
double z = ghoul::lua::value<double>(L, 3);
|
||||
lua_settop(L, 0);
|
||||
glm::dvec3 deg = galacticCartesianToIcrs(x, y, z);
|
||||
std::pair<std::string, std::string> raDecPair = decimalDegreesToIcrs(deg.x, deg.y);
|
||||
|
||||
glm::dvec3 degrees = galacticCartesianToIcrs(x, y, z);
|
||||
std::pair<std::string, std::string> raDecPair
|
||||
= decimalDegreesToIcrs(degrees.x, degrees.y);
|
||||
|
||||
ghoul::lua::push(L, raDecPair.first); // Ra
|
||||
ghoul::lua::push(L, raDecPair.second); // Dec
|
||||
ghoul::lua::push(L, degrees.z); // Distance
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 3, "Incorrect number of items left on stack");
|
||||
// Ra, Dec, Distance
|
||||
ghoul::lua::push(L, raDecPair.first, raDecPair.second, deg.z);
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,4 +52,4 @@ private:
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif __OPENSPACE_MODULE_STATEMACHINE___STATE___H__
|
||||
#endif // __OPENSPACE_MODULE_STATEMACHINE___STATE___H__
|
||||
|
||||
@@ -43,11 +43,18 @@ public:
|
||||
void transitionTo(const std::string& newState);
|
||||
bool canTransitionTo(const std::string& state) const;
|
||||
|
||||
/*
|
||||
/**
|
||||
* Return the identifiers of all possible transitions from the current state
|
||||
*/
|
||||
std::vector<std::string> possibleTransitions() const;
|
||||
|
||||
/**
|
||||
* Saves the state machine to a .dot file, as a directed graph.
|
||||
* filename is the full name of the file, including the directory,
|
||||
* but without the extension.
|
||||
*/
|
||||
void saveToDotFile(const std::string& filename) const;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
@@ -61,4 +68,4 @@ private:
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif __OPENSPACE_MODULE_STATEMACHINE___STATEMACHINE___H__
|
||||
#endif // __OPENSPACE_MODULE_STATEMACHINE___STATEMACHINE___H__
|
||||
|
||||
@@ -51,4 +51,4 @@ private:
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif __OPENSPACE_MODULE_STATEMACHINE___TRANSITION___H__
|
||||
#endif // __OPENSPACE_MODULE_STATEMACHINE___TRANSITION___H__
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
|
||||
namespace {
|
||||
@@ -195,4 +196,27 @@ std::vector<std::string> StateMachine::possibleTransitions() const {
|
||||
return res;
|
||||
}
|
||||
|
||||
void StateMachine::saveToDotFile(const std::string& filename) const {
|
||||
const std::string outputFile = filename + ".dot";
|
||||
|
||||
std::ofstream file(outputFile);
|
||||
if (!file.good()) {
|
||||
LERROR(fmt::format(
|
||||
"Error opening file {} for saving state machine dot file", outputFile
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
file << "digraph statemachine {" << std::endl;
|
||||
for (const State& s : _states) {
|
||||
file << "\t" << s.name() << ";" << std::endl;
|
||||
}
|
||||
for (const Transition& t : _transitions) {
|
||||
file << "\t" << t.from() << " -> " << t.to() << ";" << std::endl;
|
||||
}
|
||||
file << "}" << std::endl;
|
||||
|
||||
LINFO(fmt::format("Saved state machine to file: {}", outputFile));
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
#include <modules/statemachine/include/transition.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/scripting/lualibrary.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <string>
|
||||
|
||||
#include "statemachinemodule_lua.inl"
|
||||
|
||||
@@ -73,7 +75,7 @@ bool StateMachineModule::hasStateMachine() const {
|
||||
|
||||
void StateMachineModule::setInitialState(const std::string initialState) {
|
||||
if (!_machine) {
|
||||
LWARNING("Attempting to use uninitialized state machine");
|
||||
LERROR("Attempting to use uninitialized state machine");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,7 +84,7 @@ void StateMachineModule::setInitialState(const std::string initialState) {
|
||||
|
||||
std::string StateMachineModule::currentState() const {
|
||||
if (!_machine || !_machine->currentState()) {
|
||||
LWARNING("Attempting to use uninitialized state machine");
|
||||
LERROR("Attempting to use uninitialized state machine");
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -91,7 +93,7 @@ std::string StateMachineModule::currentState() const {
|
||||
|
||||
std::vector<std::string> StateMachineModule::possibleTransitions() const {
|
||||
if (!_machine) {
|
||||
LWARNING("Attempting to use uninitialized state machine");
|
||||
LERROR("Attempting to use uninitialized state machine");
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
@@ -100,7 +102,7 @@ std::vector<std::string> StateMachineModule::possibleTransitions() const {
|
||||
|
||||
void StateMachineModule::transitionTo(const std::string& newState) {
|
||||
if (!_machine) {
|
||||
LWARNING("Attempting to use uninitialized state machine");
|
||||
LERROR("Attempting to use uninitialized state machine");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -109,13 +111,29 @@ void StateMachineModule::transitionTo(const std::string& newState) {
|
||||
|
||||
bool StateMachineModule::canGoToState(const std::string& state) const {
|
||||
if (!_machine) {
|
||||
LWARNING("Attempting to use uninitialized state machine");
|
||||
LERROR("Attempting to use uninitialized state machine");
|
||||
return false;
|
||||
}
|
||||
|
||||
return _machine->canTransitionTo(state);
|
||||
}
|
||||
|
||||
void StateMachineModule::saveToFile(const std::string& filename,
|
||||
std::string directory) const
|
||||
{
|
||||
if (!_machine) {
|
||||
LERROR("Attempting to use uninitialized state machine");
|
||||
return;
|
||||
}
|
||||
|
||||
if (directory.back() != '/') {
|
||||
directory += '/';
|
||||
}
|
||||
|
||||
const std::string outputFile = absPath(directory + filename).string();
|
||||
_machine->saveToDotFile(outputFile);
|
||||
}
|
||||
|
||||
scripting::LuaLibrary StateMachineModule::luaLibrary() const {
|
||||
scripting::LuaLibrary res;
|
||||
res.name = "statemachine";
|
||||
@@ -177,6 +195,16 @@ scripting::LuaLibrary StateMachineModule::luaLibrary() const {
|
||||
{},
|
||||
"",
|
||||
"Prints information about the current state and possible transitions to the log."
|
||||
},
|
||||
{
|
||||
"saveToDotFile",
|
||||
&luascriptfunctions::saveToDotFile,
|
||||
{},
|
||||
"string, [string]",
|
||||
"Saves the current state machine to a .dot file as a directed graph. The "
|
||||
"resulting graph can be rendered using external tools such as Graphviz. "
|
||||
"The first parameter is the name of the file, and the second is an optional "
|
||||
"directory. If no directory is given, the file is saved to the temp folder."
|
||||
}
|
||||
};
|
||||
return res;
|
||||
|
||||
@@ -53,6 +53,13 @@ public:
|
||||
void transitionTo(const std::string& newState);
|
||||
bool canGoToState(const std::string& state) const;
|
||||
|
||||
/**
|
||||
* Save the state machine to a file given by the name and optional directory.
|
||||
* If no directory is given, the TEMP folder is used
|
||||
*/
|
||||
void saveToFile(const std::string& fileName,
|
||||
std::string directory = "${TEMPORARY}/") const;
|
||||
|
||||
scripting::LuaLibrary luaLibrary() const override;
|
||||
|
||||
std::vector<documentation::Documentation> documentations() const override;
|
||||
@@ -63,4 +70,4 @@ private:
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif __OPENSPACE_MODULE_STATEMACHINE___STATEMACHINEMODULE___H__
|
||||
#endif // __OPENSPACE_MODULE_STATEMACHINE___STATEMACHINEMODULE___H__
|
||||
|
||||
@@ -33,95 +33,37 @@
|
||||
namespace openspace::luascriptfunctions {
|
||||
|
||||
int createStateMachine(lua_State* L) {
|
||||
const int nArguments = ghoul::lua::checkArgumentsAndThrow(
|
||||
L,
|
||||
{ 2, 3 },
|
||||
"lua::createStateMachine"
|
||||
);
|
||||
|
||||
// If three arguments, a start state was included
|
||||
std::optional<std::string> startState = std::nullopt;
|
||||
if (nArguments > 2) {
|
||||
startState = ghoul::lua::value<std::string>(L, 3, ghoul::lua::PopValue::Yes);
|
||||
}
|
||||
|
||||
// Last dictionary is on top of the stack
|
||||
ghoul::Dictionary transitions;
|
||||
try {
|
||||
ghoul::lua::luaDictionaryFromState(L, transitions);
|
||||
}
|
||||
catch (const ghoul::lua::LuaFormatException& e) {
|
||||
LERRORC("createStateMachine", e.what());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Pop, so that first dictionary is on top and can be read
|
||||
lua_pop(L, 1);
|
||||
ghoul::Dictionary states;
|
||||
try {
|
||||
ghoul::lua::luaDictionaryFromState(L, states);
|
||||
}
|
||||
catch (const ghoul::lua::LuaFormatException& e) {
|
||||
LERRORC("createStateMachine", e.what());
|
||||
return 0;
|
||||
}
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 2, 3 }, "lua::createStateMachine");
|
||||
auto [states, transitions, startState] = ghoul::lua::values<
|
||||
ghoul::Dictionary, ghoul::Dictionary, std::optional<std::string>
|
||||
>(L);
|
||||
|
||||
StateMachineModule* module = global::moduleEngine->module<StateMachineModule>();
|
||||
|
||||
module->initializeStateMachine(states, transitions, startState);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
module->initializeStateMachine(
|
||||
std::move(states),
|
||||
std::move(transitions),
|
||||
std::move(startState)
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int goToState(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::goToState");
|
||||
const bool isString = (lua_isstring(L, 1) != 0);
|
||||
std::string newState = ghoul::lua::value<std::string>(L);
|
||||
|
||||
if (!isString) {
|
||||
lua_settop(L, 0);
|
||||
const char* msg = lua_pushfstring(
|
||||
L,
|
||||
"%s expected, got %s",
|
||||
lua_typename(L, LUA_TSTRING),
|
||||
luaL_typename(L, 0)
|
||||
);
|
||||
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
|
||||
}
|
||||
|
||||
const std::string newState = lua_tostring(L, 1);
|
||||
StateMachineModule* module = global::moduleEngine->module<StateMachineModule>();
|
||||
module->transitionTo(newState);
|
||||
LINFOC("StateMachine", "Transitioning to " + newState);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setInitialState(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setStartState");
|
||||
const bool isString = (lua_isstring(L, 1) != 0);
|
||||
std::string startState = ghoul::lua::value<std::string>(L);
|
||||
|
||||
if (!isString) {
|
||||
lua_settop(L, 0);
|
||||
const char* msg = lua_pushfstring(
|
||||
L,
|
||||
"%s expected, got %s",
|
||||
lua_typename(L, LUA_TSTRING),
|
||||
luaL_typename(L, 0)
|
||||
);
|
||||
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
|
||||
}
|
||||
|
||||
const std::string startState = lua_tostring(L, 1);
|
||||
StateMachineModule* module = global::moduleEngine->module<StateMachineModule>();
|
||||
module->setInitialState(startState);
|
||||
LINFOC("StateMachine", "Initial state set to: " + startState);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -130,9 +72,7 @@ int currentState(lua_State* L) {
|
||||
|
||||
StateMachineModule* module = global::moduleEngine->module<StateMachineModule>();
|
||||
std::string currentState = module->currentState();
|
||||
|
||||
lua_pushstring(L, currentState.c_str());
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
ghoul::lua::push(L, std::move(currentState));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -141,32 +81,16 @@ int possibleTransitions(lua_State* L) {
|
||||
|
||||
StateMachineModule* module = global::moduleEngine->module<StateMachineModule>();
|
||||
std::vector<std::string> transitions = module->possibleTransitions();
|
||||
|
||||
ghoul::lua::push(L, transitions);
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int canGoToState(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::canGoToState");
|
||||
const bool isString = (lua_isstring(L, 1) != 0);
|
||||
std::string state = ghoul::lua::value<std::string>(L);
|
||||
|
||||
if (!isString) {
|
||||
lua_settop(L, 0);
|
||||
const char* msg = lua_pushfstring(
|
||||
L,
|
||||
"%s expected, got %s",
|
||||
lua_typename(L, LUA_TSTRING),
|
||||
luaL_typename(L, 0)
|
||||
);
|
||||
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
|
||||
}
|
||||
|
||||
const std::string state = lua_tostring(L, 1);
|
||||
StateMachineModule* module = global::moduleEngine->module<StateMachineModule>();
|
||||
ghoul::lua::push(L, module->canGoToState(state));
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -174,7 +98,6 @@ int printCurrentStateInfo(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::printCurrentStateInfo");
|
||||
|
||||
StateMachineModule* module = global::moduleEngine->module<StateMachineModule>();
|
||||
|
||||
if (module->hasStateMachine()) {
|
||||
std::string currentState = module->currentState();
|
||||
std::vector<std::string> transitions = module->possibleTransitions();
|
||||
@@ -188,8 +111,23 @@ int printCurrentStateInfo(lua_State* L) {
|
||||
LINFOC("StateMachine", "No state machine has been created");
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int saveToDotFile(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::saveToDotFile");
|
||||
auto [filename, directory] =
|
||||
ghoul::lua::values<std::string, std::optional<std::string>>(L);
|
||||
|
||||
StateMachineModule* module = global::moduleEngine->module<StateMachineModule>();
|
||||
|
||||
if (directory.has_value()) {
|
||||
module->saveToFile(filename, *directory);
|
||||
}
|
||||
else {
|
||||
module->saveToFile(filename);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} //namespace openspace::luascriptfunctions
|
||||
|
||||
@@ -34,6 +34,7 @@ source_group("Header Files" FILES ${HEADER_FILES})
|
||||
|
||||
set(SOURCE_FILES
|
||||
syncmodule.cpp
|
||||
syncmodule_lua.inl
|
||||
syncs/httpsynchronization.cpp
|
||||
syncs/urlsynchronization.cpp
|
||||
tasks/syncassettask.cpp
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <openspace/engine/globalscallbacks.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <openspace/rendering/screenspacerenderable.h>
|
||||
#include <openspace/scripting/lualibrary.h>
|
||||
#include <openspace/util/factorymanager.h>
|
||||
#include <openspace/util/resourcesynchronization.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
@@ -40,6 +41,8 @@
|
||||
#include <ghoul/misc/memorypool.h>
|
||||
#include <ghoul/misc/templatefactory.h>
|
||||
|
||||
#include "syncmodule_lua.inl"
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyHttpSynchronizationRepositories =
|
||||
"HttpSynchronizationRepositories";
|
||||
@@ -140,4 +143,33 @@ std::vector<documentation::Documentation> SyncModule::documentations() const {
|
||||
};
|
||||
}
|
||||
|
||||
scripting::LuaLibrary SyncModule::luaLibrary() const {
|
||||
scripting::LuaLibrary res;
|
||||
res.name = "sync";
|
||||
res.functions = {
|
||||
{
|
||||
"syncResource",
|
||||
&luascriptfunctions::syncResource,
|
||||
{},
|
||||
"string, number",
|
||||
"Synchronizes the http resource identified by the name passed as the "
|
||||
"first parameter and the version provided as the second parameter. The "
|
||||
"application will hang while the data is being downloaded"
|
||||
},
|
||||
{
|
||||
"unsyncResource",
|
||||
&luascriptfunctions::unsyncResource,
|
||||
{},
|
||||
"string [, number]",
|
||||
"Unsynchronizes the http resources identified by the name passed as the "
|
||||
"first parameter by removing all data that was downloaded as part of the "
|
||||
"original synchronization. If the second parameter is provided, is it "
|
||||
"the version of the resources that is unsynchronized, if the parameter "
|
||||
"is not provided, all versions for the specified http resource are "
|
||||
"removed."
|
||||
}
|
||||
};
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -42,6 +42,8 @@ public:
|
||||
|
||||
std::vector<documentation::Documentation> documentations() const override;
|
||||
|
||||
scripting::LuaLibrary luaLibrary() const override;
|
||||
|
||||
protected:
|
||||
void internalInitialize(const ghoul::Dictionary& configuration) override;
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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/engine/globals.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
|
||||
namespace openspace::luascriptfunctions {
|
||||
|
||||
int syncResource(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::syncResource");
|
||||
auto [identifier, version] = ghoul::lua::values<std::string, double>(L);
|
||||
|
||||
ghoul::Dictionary dict;
|
||||
dict.setValue("Identifier", identifier);
|
||||
dict.setValue("Version", version);
|
||||
|
||||
const SyncModule* module = global::moduleEngine->module<SyncModule>();
|
||||
HttpSynchronization sync(
|
||||
dict,
|
||||
module->synchronizationRoot(),
|
||||
module->httpSynchronizationRepositories()
|
||||
);
|
||||
|
||||
sync.start();
|
||||
|
||||
while (sync.isSyncing()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
|
||||
ghoul::lua::push(L, sync.isResolved());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unsyncResource(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::unsyncResource");
|
||||
auto [identifier, version] = ghoul::lua::values<std::string, std::optional<int>>(L);
|
||||
|
||||
const SyncModule* module = global::moduleEngine->module<SyncModule>();
|
||||
std::filesystem::path sync = absPath(module->synchronizationRoot());
|
||||
std::filesystem::path base = sync / "http" / identifier;
|
||||
|
||||
if (!version.has_value()) {
|
||||
// If no version was provided, we remove all of the files
|
||||
std::filesystem::remove_all(base);
|
||||
}
|
||||
else {
|
||||
const int v = *version;
|
||||
|
||||
std::filesystem::path folder = base / std::to_string(v);
|
||||
std::string syncFile = std::to_string(v) + ".ossync";
|
||||
|
||||
std::filesystem::remove_all(folder);
|
||||
std::filesystem::remove(base / syncFile);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace openspace::luascriptfunctions
|
||||
@@ -276,7 +276,7 @@ void create() {
|
||||
actionManager = new (currentPos) interaction::ActionManager;
|
||||
ghoul_assert(actionManager, "No action manager");
|
||||
currentPos += sizeof(interaction::ActionManager);
|
||||
#else ^^^ WIN32 / !WIN32 vvv
|
||||
#else // ^^^ WIN32 / !WIN32 vvv
|
||||
actionManager = new interaction::ActionManager;
|
||||
#endif // WIN32
|
||||
|
||||
|
||||
@@ -34,30 +34,15 @@ namespace openspace::luascriptfunctions {
|
||||
*/
|
||||
int isLoaded(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::isLoaded");
|
||||
|
||||
const int type = lua_type(L, 1);
|
||||
if (type != LUA_TSTRING) {
|
||||
return ghoul::lua::luaError(L, "Expected argument of type 'string'");
|
||||
}
|
||||
const std::string& moduleName = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
const std::string name = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::vector<OpenSpaceModule*>& modules = global::moduleEngine->modules();
|
||||
|
||||
auto it = std::find_if(
|
||||
modules.begin(),
|
||||
modules.end(),
|
||||
[moduleName](OpenSpaceModule* module) {
|
||||
return module->identifier() == moduleName;
|
||||
}
|
||||
const auto it = std::find_if(
|
||||
modules.cbegin(), modules.cend(),
|
||||
[name](OpenSpaceModule* module) { return module->identifier() == name; }
|
||||
);
|
||||
|
||||
ghoul::lua::push(L, it != modules.end());
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
ghoul::lua::push(L, it != modules.cend());
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,25 +43,19 @@ namespace openspace::luascriptfunctions {
|
||||
*/
|
||||
int toggleShutdown(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::toggleShutdown");
|
||||
|
||||
global::openSpaceEngine->toggleShutdownMode();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* writeDocumentation():
|
||||
* Writes out documentation files
|
||||
*/
|
||||
* \ingroup LuaScripts
|
||||
* writeDocumentation():
|
||||
* Writes out documentation files
|
||||
*/
|
||||
int writeDocumentation(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::writeDocumentation");
|
||||
|
||||
global::openSpaceEngine->writeStaticDocumentation();
|
||||
global::openSpaceEngine->writeSceneDocumentation();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -72,15 +66,12 @@ int writeDocumentation(lua_State* L) {
|
||||
*/
|
||||
int addVirtualProperty(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 5, 7 }, "lua::addVirtualProperty");
|
||||
|
||||
const std::string& type = ghoul::lua::value<std::string>(L, 1);
|
||||
const std::string& name = ghoul::lua::value<std::string>(L, 2);
|
||||
const std::string& identifier = ghoul::lua::value<std::string>(L, 3);
|
||||
const std::string& description = ghoul::lua::value<std::string>(L, 4);
|
||||
auto [type, name, identifier, description] =
|
||||
ghoul::lua::values<std::string, std::string, std::string, std::string>(L);
|
||||
|
||||
std::unique_ptr<properties::Property> prop;
|
||||
if (type == "BoolProperty") {
|
||||
const bool v = ghoul::lua::value<bool>(L, 5);
|
||||
const bool v = ghoul::lua::value<bool>(L);
|
||||
prop = std::make_unique<properties::BoolProperty>(
|
||||
properties::Property::PropertyInfo {
|
||||
identifier.c_str(),
|
||||
@@ -91,10 +82,7 @@ int addVirtualProperty(lua_State* L) {
|
||||
);
|
||||
}
|
||||
else if (type == "IntProperty") {
|
||||
const int v = ghoul::lua::value<int>(L, 5);
|
||||
const int min = ghoul::lua::value<int>(L, 6);
|
||||
const int max = ghoul::lua::value<int>(L, 7);
|
||||
|
||||
auto [v, min, max] = ghoul::lua::values<int, int, int>(L);
|
||||
prop = std::make_unique<properties::IntProperty>(
|
||||
properties::Property::PropertyInfo {
|
||||
identifier.c_str(),
|
||||
@@ -107,10 +95,7 @@ int addVirtualProperty(lua_State* L) {
|
||||
);
|
||||
}
|
||||
else if (type == "FloatProperty") {
|
||||
const float v = ghoul::lua::value<float>(L, 5);
|
||||
const float min = ghoul::lua::value<float>(L, 6);
|
||||
const float max = ghoul::lua::value<float>(L, 7);
|
||||
|
||||
auto [v, min, max] = ghoul::lua::values<float, float, float>(L);
|
||||
prop = std::make_unique<properties::FloatProperty>(
|
||||
properties::Property::PropertyInfo {
|
||||
identifier.c_str(),
|
||||
@@ -132,26 +117,22 @@ int addVirtualProperty(lua_State* L) {
|
||||
);
|
||||
}
|
||||
else {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(L, fmt::format("Unknown property type '{}'", type));
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
global::virtualPropertyManager->addProperty(std::move(prop));
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* removeVirtualProperty():
|
||||
* Removes a previously added virtual property
|
||||
*/
|
||||
* \ingroup LuaScripts
|
||||
* removeVirtualProperty():
|
||||
* Removes a previously added virtual property
|
||||
*/
|
||||
int removeVirtualProperty(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeVirtualProperty");
|
||||
const std::string name = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& name = ghoul::lua::value<std::string>(L, 1);
|
||||
properties::Property* p = global::virtualPropertyManager->property(name);
|
||||
if (p) {
|
||||
global::virtualPropertyManager->removeProperty(p);
|
||||
@@ -159,39 +140,30 @@ int removeVirtualProperty(lua_State* L) {
|
||||
else {
|
||||
LWARNINGC(
|
||||
"removeVirtualProperty",
|
||||
fmt::format("Virtual Property with name '{}'' did not exist", name)
|
||||
fmt::format("Virtual Property with name '{}' did not exist", name)
|
||||
);
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* removeAllVirtualProperties():
|
||||
* Remove all registered virtual properties
|
||||
*/
|
||||
* \ingroup LuaScripts
|
||||
* removeAllVirtualProperties():
|
||||
* Remove all registered virtual properties
|
||||
*/
|
||||
int removeAllVirtualProperties(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::removeAllVirtualProperties");
|
||||
|
||||
const std::vector<properties::Property*>& ps =
|
||||
global::virtualPropertyManager->properties();
|
||||
for (properties::Property* p : ps) {
|
||||
for (properties::Property* p : global::virtualPropertyManager->properties()) {
|
||||
global::virtualPropertyManager->removeProperty(p);
|
||||
delete p;
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setScreenshotFolder(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setScreenshotFolder");
|
||||
|
||||
std::string arg = ghoul::lua::value<std::string>(L);
|
||||
lua_pop(L, 0);
|
||||
const std::string arg = ghoul::lua::value<std::string>(L);
|
||||
|
||||
std::filesystem::path folder = absPath(arg);
|
||||
if (!std::filesystem::exists(folder)) {
|
||||
@@ -215,22 +187,14 @@ int setScreenshotFolder(lua_State* L) {
|
||||
*/
|
||||
int addTag(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addTag");
|
||||
|
||||
const std::string& uri = ghoul::lua::value<std::string>(L, 1);
|
||||
std::string tag = ghoul::lua::value<std::string>(L, 2);
|
||||
lua_settop(L, 0);
|
||||
auto [uri, tag] = ghoul::lua::values<std::string, std::string>(L);
|
||||
|
||||
SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(uri);
|
||||
if (!node) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format("Unknown scene graph node type '{}'", uri)
|
||||
);
|
||||
return ghoul::lua::luaError(L, fmt::format("Unknown scene graph node '{}'", uri));
|
||||
}
|
||||
|
||||
node->addTag(std::move(tag));
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -240,41 +204,28 @@ int addTag(lua_State* L) {
|
||||
* Removes a tag from a SceneGraphNode
|
||||
*/
|
||||
int removeTag(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addTag");
|
||||
|
||||
const std::string& uri = ghoul::lua::value<std::string>(L, 1);
|
||||
const std::string& tag = ghoul::lua::value<std::string>(L, 2);
|
||||
lua_settop(L, 0);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::removeTag");
|
||||
auto [uri, tag] = ghoul::lua::values<std::string, std::string>(L);
|
||||
|
||||
SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(uri);
|
||||
if (!node) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format("Unknown scene graph node type '{}'", uri)
|
||||
);
|
||||
return ghoul::lua::luaError(L, fmt::format("Unknown scene graph node '{}'", uri));
|
||||
}
|
||||
|
||||
node->removeTag(tag);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* downloadFile():
|
||||
* Downloads a file from Lua interpreter
|
||||
*/
|
||||
* \ingroup LuaScripts
|
||||
* downloadFile():
|
||||
* Downloads a file from Lua interpreter
|
||||
*/
|
||||
int downloadFile(lua_State* L) {
|
||||
int n = ghoul::lua::checkArgumentsAndThrow(L, {2, 3}, "lua::addTag");
|
||||
|
||||
const std::string& uri = ghoul::lua::value<std::string>(L, 1);
|
||||
const std::string& savePath = ghoul::lua::value<std::string>(L, 2);
|
||||
bool waitForComplete = false;
|
||||
if (n == 3) {
|
||||
waitForComplete = ghoul::lua::value<bool>(L, 3);
|
||||
}
|
||||
lua_settop(L, 0);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 2, 3 }, "lua::downloadFile");
|
||||
auto [uri, savePath, waitForComplete] =
|
||||
ghoul::lua::values<std::string, std::string, std::optional<bool>>(L);
|
||||
waitForComplete = waitForComplete.value_or(false);
|
||||
|
||||
LINFOC("OpenSpaceEngine", fmt::format("Downloading file from {}", uri));
|
||||
std::shared_ptr<DownloadManager::FileFuture> future =
|
||||
@@ -300,21 +251,17 @@ int downloadFile(lua_State* L) {
|
||||
);
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* createSingleColorImage():
|
||||
* Creates a one pixel image with a given color and returns the path to the cached file
|
||||
*/
|
||||
* \ingroup LuaScripts
|
||||
* createSingleColorImage():
|
||||
* Creates a one pixel image with a given color and returns the path to the cached file
|
||||
*/
|
||||
int createSingleColorImage(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::createSingleColorImage");
|
||||
|
||||
const std::string& name = ghoul::lua::value<std::string>(L, 1);
|
||||
const ghoul::Dictionary& d = ghoul::lua::value<ghoul::Dictionary>(L, 2);
|
||||
lua_settop(L, 0);
|
||||
auto [name, d] = ghoul::lua::values<std::string, ghoul::Dictionary>(L);
|
||||
|
||||
// @TODO (emmbr 2020-12-18) Verify that the input dictionary is a vec3
|
||||
// Would like to clean this up with a more direct use of the Verifier in the future
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace openspace::luascriptfunctions {
|
||||
*/
|
||||
int hasAction(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::hasAction");
|
||||
const std::string identifier = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& identifier = ghoul::lua::value<std::string>(L, 1);
|
||||
if (identifier.empty()) {
|
||||
return ghoul::lua::luaError(L, "Identifier must not be empty");
|
||||
}
|
||||
@@ -51,8 +51,8 @@ int hasAction(lua_State* L) {
|
||||
*/
|
||||
int removeAction(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeAction");
|
||||
const std::string identifier = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& identifier = ghoul::lua::value<std::string>(L, 1);
|
||||
if (identifier.empty()) {
|
||||
return ghoul::lua::luaError(L, "Identifier must not be empty");
|
||||
}
|
||||
@@ -63,7 +63,6 @@ int removeAction(lua_State* L) {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
global::actionManager->removeAction(identifier);
|
||||
return 0;
|
||||
}
|
||||
@@ -81,8 +80,7 @@ int removeAction(lua_State* L) {
|
||||
*/
|
||||
int registerAction(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::registerAction");
|
||||
|
||||
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L, 1);
|
||||
const ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
if (!d.hasValue<std::string>("Identifier")) {
|
||||
return ghoul::lua::luaError(L, "Identifier must to provided to register action");
|
||||
@@ -138,8 +136,8 @@ int registerAction(lua_State* L) {
|
||||
*/
|
||||
int action(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::action");
|
||||
const std::string identifier = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& identifier = ghoul::lua::value<std::string>(L, 1);
|
||||
if (identifier.empty()) {
|
||||
return ghoul::lua::luaError(L, "Identifier must not be empty");
|
||||
}
|
||||
@@ -168,7 +166,6 @@ int action(lua_State* L) {
|
||||
action.synchronization == interaction::Action::IsSynchronized::Yes
|
||||
);
|
||||
lua_settable(L, -3);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -216,25 +213,18 @@ int actions(lua_State* L) {
|
||||
* Triggers the action given by the specified identifier.
|
||||
*/
|
||||
int triggerAction(lua_State* L) {
|
||||
int n = ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::triggerAction");
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::triggerAction");
|
||||
auto [id, arg] = ghoul::lua::values<std::string, std::optional<ghoul::Dictionary>>(L);
|
||||
arg = arg.value_or(ghoul::Dictionary());
|
||||
|
||||
const std::string& identifier = ghoul::lua::value<std::string>(L, 1);
|
||||
if (identifier.empty()) {
|
||||
if (id.empty()) {
|
||||
return ghoul::lua::luaError(L, "Identifier must not be empty");
|
||||
}
|
||||
if (!global::actionManager->hasAction(identifier)) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format("Identifier '{}' for action not found", identifier)
|
||||
);
|
||||
if (!global::actionManager->hasAction(id)) {
|
||||
return ghoul::lua::luaError(L, fmt::format("Action '{}' not found", id));
|
||||
}
|
||||
|
||||
ghoul::Dictionary arguments;
|
||||
if (n == 2) {
|
||||
ghoul::lua::luaDictionaryFromState(L, arguments, 2);
|
||||
}
|
||||
|
||||
global::actionManager->triggerAction(identifier, arguments);
|
||||
global::actionManager->triggerAction(id, *arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,35 +34,24 @@ namespace openspace::luascriptfunctions {
|
||||
* node is hosting a parallel connection.
|
||||
*/
|
||||
int bindKey(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::bindKey");
|
||||
|
||||
std::string key = ghoul::lua::value<std::string>(L, 1);
|
||||
std::string action = ghoul::lua::value<std::string>(L, 2);
|
||||
auto [key, action] = ghoul::lua::values<std::string, std::string>(L);
|
||||
|
||||
if (action.empty()) {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(L, "Action must not be empty");
|
||||
}
|
||||
if (!global::actionManager->hasAction(action)) {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(L, fmt::format("Action '{}' does not exist", action));
|
||||
}
|
||||
|
||||
openspace::KeyWithModifier iKey = openspace::stringToKey(key);
|
||||
|
||||
if (iKey.key == openspace::Key::Unknown) {
|
||||
std::string error = fmt::format("Could not find key '{}'", key);
|
||||
LERRORC("lua.bindKey", error);
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(L, error);
|
||||
}
|
||||
|
||||
global::keybindingManager->bindKey(iKey.key, iKey.modifier, std::move(action));
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -74,16 +63,10 @@ int bindKey(lua_State* L) {
|
||||
*/
|
||||
int getKeyBindings(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::getKeyBindings");
|
||||
|
||||
const std::string& key = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
const std::string& key = ghoul::lua::value<std::string>(L);
|
||||
|
||||
using K = KeyWithModifier;
|
||||
using V = std::string;
|
||||
|
||||
const std::vector<std::pair<K, V>>& info = global::keybindingManager->keyBinding(
|
||||
stringToKey(key)
|
||||
);
|
||||
@@ -97,7 +80,6 @@ int getKeyBindings(lua_State* L) {
|
||||
++i;
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -109,25 +91,18 @@ int getKeyBindings(lua_State* L) {
|
||||
int clearKey(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::clearKey");
|
||||
|
||||
const int t = lua_type(L, 1);
|
||||
if (t == LUA_TSTRING) {
|
||||
// The user provided a single key
|
||||
const std::string& key = ghoul::lua::value<std::string>(L, 1);
|
||||
global::keybindingManager->removeKeyBinding(stringToKey(key));
|
||||
std::variant key = ghoul::lua::value<std::variant<std::string, ghoul::Dictionary>>(L);
|
||||
if (std::holds_alternative<std::string>(key)) {
|
||||
KeyWithModifier k = stringToKey(std::get<std::string>(key));
|
||||
global::keybindingManager->removeKeyBinding(k);
|
||||
}
|
||||
else {
|
||||
// The user provided a list of keys
|
||||
ghoul::Dictionary d;
|
||||
ghoul::lua::luaDictionaryFromState(L, d);
|
||||
ghoul::Dictionary d = std::get<ghoul::Dictionary>(key);
|
||||
for (size_t i = 1; i <= d.size(); ++i) {
|
||||
const std::string& k = d.value<std::string>(std::to_string(i));
|
||||
global::keybindingManager->removeKeyBinding(stringToKey(k));
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -138,10 +113,7 @@ int clearKey(lua_State* L) {
|
||||
*/
|
||||
int clearKeys(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::clearKeys");
|
||||
|
||||
global::keybindingManager->resetKeyBindings();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,17 +24,9 @@
|
||||
|
||||
namespace openspace::luascriptfunctions {
|
||||
|
||||
|
||||
int startRecording(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startRecording");
|
||||
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
const std::string recordFilePath = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
const std::string recordFilePath = ghoul::lua::value<std::string>(L);
|
||||
|
||||
if (recordFilePath.empty()) {
|
||||
return luaL_error(L, "filepath string is empty");
|
||||
@@ -43,21 +35,12 @@ int startRecording(lua_State* L) {
|
||||
interaction::SessionRecording::DataMode::Binary
|
||||
);
|
||||
global::sessionRecording->startRecording(recordFilePath);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int startRecordingAscii(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startRecordingAscii");
|
||||
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
const std::string recordFilePath = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
const std::string recordFilePath = ghoul::lua::value<std::string>(L);
|
||||
|
||||
if (recordFilePath.empty()) {
|
||||
return luaL_error(L, "filepath string is empty");
|
||||
@@ -66,196 +49,109 @@ int startRecordingAscii(lua_State* L) {
|
||||
interaction::SessionRecording::DataMode::Ascii
|
||||
);
|
||||
global::sessionRecording->startRecording(recordFilePath);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stopRecording(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::stopRecording");
|
||||
|
||||
global::sessionRecording->stopRecording();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int startPlayback(lua_State* L, interaction::KeyframeTimeRef timeMode,
|
||||
bool forceSimTimeAtStart)
|
||||
{
|
||||
using ghoul::lua::luaTypeToString;
|
||||
const int nArguments = lua_gettop(L);
|
||||
bool loop = false;
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::startPlayback");
|
||||
auto [file, loop] = ghoul::lua::values<std::string, std::optional<bool>>(L);
|
||||
loop = loop.value_or(false);
|
||||
|
||||
if (nArguments == 2) {
|
||||
loop = lua_toboolean(L, 2) == 1;
|
||||
if (file.empty()) {
|
||||
return ghoul::lua::luaError(L, "Filepath string is empty");
|
||||
}
|
||||
else if (nArguments != 1) {
|
||||
lua_settop(L, 0);
|
||||
return luaL_error(
|
||||
L,
|
||||
"bad number of arguments, expected 1 or 2, got %i",
|
||||
nArguments
|
||||
);
|
||||
}
|
||||
|
||||
const std::string playbackFilePath = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
|
||||
if (playbackFilePath.empty()) {
|
||||
return luaL_error(L, "filepath string is empty");
|
||||
}
|
||||
|
||||
global::sessionRecording->startPlayback(
|
||||
const_cast<std::string&>(playbackFilePath),
|
||||
timeMode,
|
||||
forceSimTimeAtStart,
|
||||
loop
|
||||
);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
global::sessionRecording->startPlayback(file, timeMode, forceSimTimeAtStart, *loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int startPlaybackDefault(lua_State* L) {
|
||||
using interaction::KeyframeNavigator;
|
||||
ghoul::lua::checkArgumentsAndThrow(L, {1, 2}, "lua::startPlaybackDefault");
|
||||
return startPlayback(L,
|
||||
interaction::KeyframeTimeRef::Relative_recordedStart, true);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::startPlaybackDefault");
|
||||
return startPlayback(L, interaction::KeyframeTimeRef::Relative_recordedStart, true);
|
||||
}
|
||||
|
||||
int startPlaybackApplicationTime(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackApplicationTime");
|
||||
|
||||
return startPlayback(L,
|
||||
interaction::KeyframeTimeRef::Relative_applicationStart, false);
|
||||
return startPlayback(
|
||||
L,
|
||||
interaction::KeyframeTimeRef::Relative_applicationStart,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
int startPlaybackRecordedTime(lua_State* L) {
|
||||
using interaction::KeyframeNavigator;
|
||||
ghoul::lua::checkArgumentsAndThrow(L, {1, 2}, "lua::startPlaybackRecordedTime");
|
||||
return startPlayback(L,
|
||||
interaction::KeyframeTimeRef::Relative_recordedStart, false);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::startPlaybackRecordedTime");
|
||||
return startPlayback(L, interaction::KeyframeTimeRef::Relative_recordedStart, false);
|
||||
}
|
||||
|
||||
int startPlaybackSimulationTime(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackSimulationTime");
|
||||
using interaction::KeyframeNavigator;
|
||||
return startPlayback(L,
|
||||
interaction::KeyframeTimeRef::Absolute_simTimeJ2000, false);
|
||||
return startPlayback(L, interaction::KeyframeTimeRef::Absolute_simTimeJ2000, false);
|
||||
}
|
||||
|
||||
int stopPlayback(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::stopPlayback");
|
||||
|
||||
global::sessionRecording->stopPlayback();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int enableTakeScreenShotDuringPlayback(lua_State* L) {
|
||||
const int nArguments = ghoul::lua::checkArgumentsAndThrow(
|
||||
ghoul::lua::checkArgumentsAndThrow(
|
||||
L,
|
||||
{ 0, 1 },
|
||||
"lua::enableTakeScreenShotDuringPlayback"
|
||||
);
|
||||
std::optional<int> fps = ghoul::lua::value<std::optional<int>>(L);
|
||||
fps = fps.value_or(60);
|
||||
|
||||
const int fps = nArguments == 0 ? 60 : ghoul::lua::value<int>(L, 1);
|
||||
|
||||
global::sessionRecording->enableTakeScreenShotDuringPlayback(fps);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
global::sessionRecording->enableTakeScreenShotDuringPlayback(*fps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disableTakeScreenShotDuringPlayback(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableTakeScreenShotDuringPlayback");
|
||||
|
||||
global::sessionRecording->disableTakeScreenShotDuringPlayback();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fileFormatConversion(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
const std::string convertFilePath = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::fileFormatConversion");
|
||||
const std::string convertFilePath = ghoul::lua::value<std::string>(L);
|
||||
|
||||
if (convertFilePath.empty()) {
|
||||
return luaL_error(L, "filepath string is empty");
|
||||
return luaL_error(L, "Filepath string must not be empty");
|
||||
}
|
||||
global::sessionRecording->convertFile(convertFilePath);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setPlaybackPause(lua_State* L) {
|
||||
const int nArguments = lua_gettop(L);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setPlaybackPause");
|
||||
const bool pause = ghoul::lua::value<bool>(L);
|
||||
|
||||
if (nArguments == 1) {
|
||||
const bool pause = lua_toboolean(L, 1) == 1;
|
||||
global::sessionRecording->setPlaybackPause(pause);
|
||||
}
|
||||
else {
|
||||
lua_settop(L, 0);
|
||||
return luaL_error(
|
||||
L,
|
||||
"bad number of arguments, expected 1, got %i",
|
||||
nArguments
|
||||
);
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
global::sessionRecording->setPlaybackPause(pause);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int togglePlaybackPause(lua_State* L) {
|
||||
const int nArguments = lua_gettop(L);
|
||||
|
||||
if (nArguments == 0) {
|
||||
bool isPlaybackPaused = global::sessionRecording->isPlaybackPaused();
|
||||
global::sessionRecording->setPlaybackPause(!isPlaybackPaused);
|
||||
}
|
||||
else {
|
||||
lua_settop(L, 0);
|
||||
return luaL_error(
|
||||
L,
|
||||
"bad number of arguments, expected 0, got %i",
|
||||
nArguments
|
||||
);
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::togglePlaybackPause");
|
||||
bool isPlaybackPaused = global::sessionRecording->isPlaybackPaused();
|
||||
global::sessionRecording->setPlaybackPause(!isPlaybackPaused);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isPlayingBack(lua_State* L) {
|
||||
const int nArguments = lua_gettop(L);
|
||||
|
||||
if (nArguments != 0) {
|
||||
lua_settop(L, 0);
|
||||
return luaL_error(
|
||||
L,
|
||||
"bad number of arguments, expected 0, got %i",
|
||||
nArguments
|
||||
);
|
||||
}
|
||||
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::isPlayingBack");
|
||||
ghoul::lua::push(L, global::sessionRecording->isPlayingBack());
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,21 +105,19 @@ void ConvertRecFormatTask::convert() {
|
||||
expectedFileExtension_out = SessionRecording::FileExtensionBinary;
|
||||
}
|
||||
|
||||
if (std::filesystem::path(_inFilePath).extension() != expectedFileExtension_in) {
|
||||
if (_inFilePath.extension() != expectedFileExtension_in) {
|
||||
LWARNING(fmt::format(
|
||||
"Input filename doesn't have expected {} format file extension", currentFormat
|
||||
));
|
||||
}
|
||||
if (std::filesystem::path(_outFilePath).extension() == expectedFileExtension_in) {
|
||||
if (_outFilePath.extension() == expectedFileExtension_in) {
|
||||
LERROR(fmt::format(
|
||||
"Output filename has {} file extension, but is conversion from {}",
|
||||
currentFormat, currentFormat
|
||||
));
|
||||
return;
|
||||
}
|
||||
else if (std::filesystem::path(_outFilePath).extension() !=
|
||||
expectedFileExtension_out)
|
||||
{
|
||||
else if (_outFilePath.extension() != expectedFileExtension_out) {
|
||||
_outFilePath += expectedFileExtension_out;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,33 +28,21 @@ namespace openspace::luascriptfunctions {
|
||||
|
||||
int loadMission(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadMission");
|
||||
const std::string& missionFileName = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& missionFileName = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
if (missionFileName.empty()) {
|
||||
return ghoul::lua::luaError(L, "Filepath is empty");
|
||||
}
|
||||
|
||||
std::string name = global::missionManager->loadMission(
|
||||
absPath(missionFileName).string()
|
||||
);
|
||||
const std::string name = global::missionManager->loadMission(missionFileName);
|
||||
ghoul::lua::push(L, name);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unloadMission(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unloadMission");
|
||||
const std::string missionName = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& missionName = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
if (missionName.empty()) {
|
||||
return ghoul::lua::luaError(L, "Mission name is empty");
|
||||
}
|
||||
@@ -64,46 +52,30 @@ int unloadMission(lua_State* L) {
|
||||
}
|
||||
|
||||
global::missionManager->unloadMission(missionName);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hasMission(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::hasMission");
|
||||
const std::string missionName = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& missionName = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
if (missionName.empty()) {
|
||||
return ghoul::lua::luaError(L, "Missing name is empty");
|
||||
}
|
||||
|
||||
const bool hasMission = global::missionManager->hasMission(missionName);
|
||||
|
||||
ghoul::lua::push(L, hasMission);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int setCurrentMission(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setCurrentMission");
|
||||
const std::string missionName = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& missionName = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
if (missionName.empty()) {
|
||||
return ghoul::lua::luaError(L, "Mission name is empty");
|
||||
}
|
||||
|
||||
global::missionManager->setCurrentMission(missionName);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,41 +30,28 @@ namespace openspace::luascriptfunctions {
|
||||
|
||||
int loadNavigationState(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadNavigationState");
|
||||
|
||||
const std::string& cameraStateFilePath = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
const std::string cameraStateFilePath = ghoul::lua::value<std::string>(L);
|
||||
|
||||
if (cameraStateFilePath.empty()) {
|
||||
return ghoul::lua::luaError(L, "filepath string is empty");
|
||||
}
|
||||
|
||||
global::navigationHandler->loadNavigationState(cameraStateFilePath);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getNavigationState(lua_State* L) {
|
||||
const int n = ghoul::lua::checkArgumentsAndThrow(
|
||||
L,
|
||||
{ 0, 1 },
|
||||
"lua::getNavigationState"
|
||||
);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 0, 1 }, "lua::getNavigationState");
|
||||
std::optional<std::string> frame = ghoul::lua::value<std::optional<std::string>>(L);
|
||||
|
||||
interaction::NavigationState state;
|
||||
if (n == 1) {
|
||||
const std::string referenceFrameIdentifier = ghoul::lua::value<std::string>(L, 1);
|
||||
const SceneGraphNode* referenceFrame = sceneGraphNode(referenceFrameIdentifier);
|
||||
if (frame.has_value()) {
|
||||
const SceneGraphNode* referenceFrame = sceneGraphNode(*frame);
|
||||
if (!referenceFrame) {
|
||||
LERROR(fmt::format(
|
||||
"Could not find node '{}' to use as reference frame",
|
||||
referenceFrameIdentifier
|
||||
));
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format("Could not find node '{}' as reference frame", *frame)
|
||||
);
|
||||
}
|
||||
state = global::navigationHandler->navigationState(*referenceFrame);
|
||||
}
|
||||
@@ -72,7 +59,6 @@ int getNavigationState(lua_State* L) {
|
||||
state = global::navigationHandler->navigationState();
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
|
||||
const auto pushVector = [](lua_State* s, const glm::dvec3& v) {
|
||||
lua_newtable(s);
|
||||
@@ -114,15 +100,12 @@ int getNavigationState(lua_State* L) {
|
||||
lua_rawset(L, -3);
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int setNavigationState(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setNavigationState");
|
||||
|
||||
ghoul::Dictionary navigationStateDictionary;
|
||||
ghoul::lua::luaDictionaryFromState(L, navigationStateDictionary);
|
||||
ghoul::Dictionary navigationStateDictionary = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
openspace::documentation::TestResult r = openspace::documentation::testSpecification(
|
||||
interaction::NavigationState::Documentation(),
|
||||
@@ -130,278 +113,196 @@ int setNavigationState(lua_State* L) {
|
||||
);
|
||||
|
||||
if (!r.success) {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(
|
||||
L, fmt::format("Could not set camera state: {}", ghoul::to_string(r))
|
||||
L,
|
||||
fmt::format("Could not set camera state: {}", ghoul::to_string(r))
|
||||
);
|
||||
}
|
||||
|
||||
global::navigationHandler->setNavigationStateNextFrame(
|
||||
interaction::NavigationState(navigationStateDictionary)
|
||||
);
|
||||
|
||||
// @CLEANUP: When luaDictionaryFromState doesn't leak space anymore, remove the next
|
||||
// line ---abock(2018-02-15)
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int saveNavigationState(lua_State* L) {
|
||||
const int n = ghoul::lua::checkArgumentsAndThrow(
|
||||
L,
|
||||
{ 1, 2 },
|
||||
"lua::saveNavigationState"
|
||||
);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::saveNavigationState");
|
||||
auto [path, frame] = ghoul::lua::values<std::string, std::optional<std::string>>(L);
|
||||
frame = frame.value_or("");
|
||||
|
||||
const std::string& cameraStateFilePath = ghoul::lua::value<std::string>(L, 1);
|
||||
|
||||
std::string referenceFrame = "";
|
||||
if (n > 1) {
|
||||
referenceFrame = ghoul::lua::value<std::string>(L, 2);
|
||||
if (path.empty()) {
|
||||
return ghoul::lua::luaError(L, "Filepath string is empty");
|
||||
}
|
||||
|
||||
if (cameraStateFilePath.empty()) {
|
||||
return ghoul::lua::luaError(L, "filepath string is empty");
|
||||
}
|
||||
|
||||
global::navigationHandler->saveNavigationState(cameraStateFilePath, referenceFrame);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
global::navigationHandler->saveNavigationState(path, *frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int retargetAnchor(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::retargetAnchor");
|
||||
|
||||
global::navigationHandler->orbitalNavigator().startRetargetAnchor();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int retargetAim(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::retargetAim");
|
||||
|
||||
global::navigationHandler->orbitalNavigator().startRetargetAim();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bindJoystickAxis(lua_State* L) {
|
||||
const int n = ghoul::lua::checkArgumentsAndThrow(
|
||||
L,
|
||||
{ 2, 6 },
|
||||
"lua::bindJoystickAxis"
|
||||
);
|
||||
|
||||
const int axis = ghoul::lua::value<int>(L, 1);
|
||||
const std::string& axisType = ghoul::lua::value<std::string>(L, 2);
|
||||
|
||||
const bool shouldInvert = n > 2 ? ghoul::lua::value<bool>(L, 3) : false;
|
||||
const bool shouldNormalize = n > 3 ? ghoul::lua::value<bool>(L, 4) : false;
|
||||
const bool isSticky = n > 4 ? ghoul::lua::value<bool>(L, 5) : false;
|
||||
const double sensitivity = n > 5 ? ghoul::lua::value<double>(L, 6) : 0.0;
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 2, 6 }, "lua::bindJoystickAxis");
|
||||
auto [axis, axisType, shouldInvert, shouldNormalize, isSticky, sensitivity] =
|
||||
ghoul::lua::values<
|
||||
int, std::string, std::optional<bool>, std::optional<bool>,
|
||||
std::optional<bool>, std::optional<double>
|
||||
>(L);
|
||||
shouldInvert = shouldInvert.value_or(false);
|
||||
shouldNormalize = shouldNormalize.value_or(false);
|
||||
isSticky = isSticky.value_or(false);
|
||||
sensitivity = sensitivity.value_or(0.0);
|
||||
|
||||
global::navigationHandler->setJoystickAxisMapping(
|
||||
axis,
|
||||
ghoul::from_string<interaction::JoystickCameraStates::AxisType>(axisType),
|
||||
interaction::JoystickCameraStates::AxisInvert(shouldInvert),
|
||||
interaction::JoystickCameraStates::AxisNormalize(shouldNormalize),
|
||||
isSticky,
|
||||
sensitivity
|
||||
interaction::JoystickCameraStates::AxisInvert(*shouldInvert),
|
||||
interaction::JoystickCameraStates::AxisNormalize(*shouldNormalize),
|
||||
*isSticky,
|
||||
*sensitivity
|
||||
);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int joystickAxis(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickAxis");
|
||||
|
||||
const int axis = ghoul::lua::value<int>(L, 1);
|
||||
const int axis = ghoul::lua::value<int>(L);
|
||||
|
||||
using AI = interaction::JoystickCameraStates::AxisInformation;
|
||||
AI info = global::navigationHandler->joystickAxisMapping(axis);
|
||||
|
||||
lua_settop(L, 0);
|
||||
const bool invert = info.invert;
|
||||
const bool normalize = info.normalize;
|
||||
const bool isSticky = info.isSticky;
|
||||
const double sensitivity = info.sensitivity;
|
||||
ghoul::lua::push(
|
||||
L,
|
||||
ghoul::to_string(info.type),
|
||||
invert,
|
||||
normalize,
|
||||
isSticky,
|
||||
sensitivity
|
||||
static_cast<bool>(info.invert),
|
||||
static_cast<bool>(info.normalize),
|
||||
info.isSticky,
|
||||
info.sensitivity
|
||||
);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 5, "Incorrect number of items left on stack");
|
||||
return 5;
|
||||
}
|
||||
|
||||
int setJoystickAxisDeadzone(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::setJoystickAxisDeadzone");
|
||||
|
||||
const int axis = ghoul::lua::value<int>(L, 1);
|
||||
const float deadzone = ghoul::lua::value<float>(L, 2);
|
||||
lua_settop(L, 0);
|
||||
auto [axis, deadzone] = ghoul::lua::values<int, float>(L);
|
||||
|
||||
global::navigationHandler->setJoystickAxisDeadzone(axis, deadzone);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int joystickAxisDeadzone(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setJoystickAxisDeadzone");
|
||||
|
||||
const int axis = ghoul::lua::value<int>(L, 1, ghoul::lua::PopValue::Yes);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickAxisDeadzone");
|
||||
const int axis = ghoul::lua::value<int>(L);
|
||||
|
||||
const float deadzone = global::navigationHandler->joystickAxisDeadzone(axis);
|
||||
|
||||
ghoul::lua::push(L, deadzone);
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int bindJoystickButton(lua_State* L) {
|
||||
const int n = ghoul::lua::checkArgumentsAndThrow(
|
||||
L,
|
||||
{ 3, 5 },
|
||||
"lua::bindJoystickButton"
|
||||
);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 3, 5 }, "lua::bindJoystickButton");
|
||||
auto [button, command, documentation, actionStr, isRemote] =
|
||||
ghoul::lua::values<
|
||||
int, std::string, std::string, std::optional<std::string>, std::optional<bool>
|
||||
>(L);
|
||||
actionStr = actionStr.value_or("Press");
|
||||
isRemote = isRemote.value_or(true);
|
||||
|
||||
const int button = ghoul::lua::value<int>(L, 1);
|
||||
std::string command = ghoul::lua::value<std::string>(L, 2);
|
||||
std::string documentation = ghoul::lua::value<std::string>(L, 3);
|
||||
|
||||
interaction::JoystickAction action = interaction::JoystickAction::Press;
|
||||
if (n >= 4) {
|
||||
const std::string& actionStr = ghoul::lua::value<std::string>(L, 4);
|
||||
action = ghoul::from_string<interaction::JoystickAction>(actionStr);
|
||||
}
|
||||
|
||||
const bool isRemote = n == 5 ? ghoul::lua::value<bool>(L, 5) : true;
|
||||
lua_settop(L, 0);
|
||||
interaction::JoystickAction action =
|
||||
ghoul::from_string<interaction::JoystickAction>(*actionStr);
|
||||
|
||||
global::navigationHandler->bindJoystickButtonCommand(
|
||||
button,
|
||||
command,
|
||||
action,
|
||||
interaction::JoystickCameraStates::ButtonCommandRemote(isRemote),
|
||||
interaction::JoystickCameraStates::ButtonCommandRemote(*isRemote),
|
||||
documentation
|
||||
);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clearJoystickButton(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::bindJoystickButton");
|
||||
|
||||
const int button = ghoul::lua::value<int>(L, 1, ghoul::lua::PopValue::Yes);
|
||||
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::clearJoystickButton");
|
||||
const int button = ghoul::lua::value<int>(L);
|
||||
global::navigationHandler->clearJoystickButtonCommand(button);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int joystickButton(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::bindJoystickButton");
|
||||
|
||||
const int button = ghoul::lua::value<int>(L, 1, ghoul::lua::PopValue::Yes);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickButton");
|
||||
const int button = ghoul::lua::value<int>(L);
|
||||
|
||||
const std::vector<std::string>& cmds =
|
||||
global::navigationHandler->joystickButtonCommand(button);
|
||||
|
||||
std::string cmd = std::accumulate(
|
||||
cmds.begin(),
|
||||
cmds.end(),
|
||||
cmds.cbegin(),
|
||||
cmds.cend(),
|
||||
std::string(),
|
||||
[](const std::string& lhs, const std::string& rhs) {
|
||||
return lhs + ";" + rhs;
|
||||
}
|
||||
);
|
||||
|
||||
ghoul::lua::push(L, cmd);
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int addGlobalRotation(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addGlobalRotation");
|
||||
|
||||
const double v1 = ghoul::lua::value<double>(L, 1, ghoul::lua::PopValue::No);
|
||||
const double v2 = ghoul::lua::value<double>(L, 2, ghoul::lua::PopValue::No);
|
||||
auto [v1, v2] = ghoul::lua::values<double, double>(L);
|
||||
|
||||
global::navigationHandler->orbitalNavigator().scriptStates().addGlobalRotation(
|
||||
glm::dvec2(v1, v2)
|
||||
);
|
||||
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addLocalRotation(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addLocalRotation");
|
||||
|
||||
const double v1 = ghoul::lua::value<double>(L, 1, ghoul::lua::PopValue::No);
|
||||
const double v2 = ghoul::lua::value<double>(L, 2, ghoul::lua::PopValue::No);
|
||||
auto [v1, v2] = ghoul::lua::values<double, double>(L);
|
||||
|
||||
global::navigationHandler->orbitalNavigator().scriptStates().addLocalRotation(
|
||||
glm::dvec2(v1, v2)
|
||||
);
|
||||
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addTruckMovement(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addTruckMovement");
|
||||
|
||||
const double v1 = ghoul::lua::value<double>(L, 1, ghoul::lua::PopValue::No);
|
||||
const double v2 = ghoul::lua::value<double>(L, 2, ghoul::lua::PopValue::No);
|
||||
auto [v1, v2] = ghoul::lua::values<double, double>(L);
|
||||
|
||||
global::navigationHandler->orbitalNavigator().scriptStates().addTruckMovement(
|
||||
glm::dvec2(v1, v2)
|
||||
);
|
||||
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addLocalRoll(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addLocalRoll");
|
||||
|
||||
const double v1 = ghoul::lua::value<double>(L, 1, ghoul::lua::PopValue::No);
|
||||
const double v2 = ghoul::lua::value<double>(L, 2, ghoul::lua::PopValue::No);
|
||||
auto [v1, v2] = ghoul::lua::values<double, double>(L);
|
||||
|
||||
global::navigationHandler->orbitalNavigator().scriptStates().addLocalRoll(
|
||||
glm::dvec2(v1, v2)
|
||||
);
|
||||
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addGlobalRoll(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addGlobalRoll");
|
||||
|
||||
const double v1 = ghoul::lua::value<double>(L, 1, ghoul::lua::PopValue::No);
|
||||
const double v2 = ghoul::lua::value<double>(L, 2, ghoul::lua::PopValue::No);
|
||||
auto [v1, v2] = ghoul::lua::values<double, double>(L);
|
||||
|
||||
global::navigationHandler->orbitalNavigator().scriptStates().addGlobalRoll(
|
||||
glm::dvec2(v1, v2)
|
||||
);
|
||||
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,8 +121,7 @@ CameraPose NavigationState::cameraPose() const {
|
||||
const glm::dvec3 anchorWorldPosition = anchorNode->worldPosition();
|
||||
const glm::dmat3 referenceFrameTransform = referenceFrameNode->worldRotationMatrix();
|
||||
|
||||
resultingPose.position = anchorWorldPosition +
|
||||
glm::dvec3(referenceFrameTransform * glm::dvec4(position, 1.0));
|
||||
resultingPose.position = anchorWorldPosition + referenceFrameTransform * position;
|
||||
|
||||
glm::dvec3 upVector = up.has_value() ?
|
||||
glm::normalize(referenceFrameTransform * up.value()) :
|
||||
|
||||
@@ -310,7 +310,8 @@ OrbitalNavigator::IdleBehavior::IdleBehavior()
|
||||
addProperty(apply);
|
||||
chosenBehavior.addOptions({
|
||||
{ IdleBehavior::Behavior::Orbit, "Orbit" },
|
||||
{ IdleBehavior::Behavior::OrbitAtConstantLat, "OrbitAtConstantLatitude" }
|
||||
{ IdleBehavior::Behavior::OrbitAtConstantLat, "OrbitAtConstantLatitude" },
|
||||
{ IdleBehavior::Behavior::OrbitAroundUp, "OrbitAroundUp" }
|
||||
});
|
||||
chosenBehavior = IdleBehavior::Behavior::Orbit;
|
||||
addProperty(chosenBehavior);
|
||||
@@ -572,7 +573,7 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) {
|
||||
// Calculate a position handle based on the camera position in world space
|
||||
glm::dvec3 camPosToAnchorPosDiff = prevCameraPosition - anchorPos;
|
||||
// Use the interaction sphere to get an approximate distance to the node surface
|
||||
double nodeRadius = static_cast<double>(_anchorNode->interactionSphere());
|
||||
double nodeRadius = _anchorNode->interactionSphere();
|
||||
double distFromCameraToFocus =
|
||||
glm::distance(prevCameraPosition, anchorPos) - nodeRadius;
|
||||
|
||||
@@ -1614,9 +1615,21 @@ void OrbitalNavigator::applyIdleBehavior(double deltaTime, glm::dvec3& position,
|
||||
case IdleBehavior::Behavior::Orbit:
|
||||
orbitAnchor(deltaTime, position, globalRotation, speedScale);
|
||||
break;
|
||||
case IdleBehavior::Behavior::OrbitAtConstantLat:
|
||||
orbitAtConstantLatitude(deltaTime, position, globalRotation, speedScale);
|
||||
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.
|
||||
// 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);
|
||||
break;
|
||||
}
|
||||
case IdleBehavior::Behavior::OrbitAroundUp: {
|
||||
// Assume that "up" coincides with the local y-direction
|
||||
const glm::dvec3 up = glm::dvec3(0.0, 1.0, 0.0);
|
||||
orbitAroundAxis(up, deltaTime, position, globalRotation, speedScale);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
@@ -1645,24 +1658,19 @@ void OrbitalNavigator::orbitAnchor(double deltaTime, glm::dvec3& position,
|
||||
position += rotationDiffVec3;
|
||||
}
|
||||
|
||||
void OrbitalNavigator::orbitAtConstantLatitude(double deltaTime, glm::dvec3& position,
|
||||
glm::dquat& globalRotation,
|
||||
double speedScale)
|
||||
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 =
|
||||
glm::dmat3(modelTransform) * glm::normalize(axis);
|
||||
|
||||
// Assume 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
|
||||
const glm::dvec3 northInWorldCoords =
|
||||
glm::dmat3(modelTransform) * glm::dvec3(0.0, 0.0, 1.0);
|
||||
|
||||
// Compute rotation around the north axis to be applied
|
||||
// Compute rotation to be applied around the axis
|
||||
double angle = deltaTime * speedScale;
|
||||
const glm::dquat spinRotation =
|
||||
glm::angleAxis(angle, glm::normalize(northInWorldCoords));
|
||||
const glm::dquat spinRotation = glm::angleAxis(angle, axisInWorldCoords);
|
||||
|
||||
// Rotate the position vector from the center to camera and update position
|
||||
const glm::dvec3 anchorCenterToCamera = position - _anchorNode->worldPosition();
|
||||
|
||||
+15
-15
@@ -107,19 +107,19 @@ Path::Path(Waypoint start, Waypoint end, Type type,
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
|
||||
_duration = duration.value_or(std::log(pathLength()));
|
||||
// Compute speed factor to match any given duration, by traversing the path and
|
||||
// computing how much faster/slower it should be
|
||||
_speedFactorFromDuration = 1.0;
|
||||
if (duration.has_value()) {
|
||||
constexpr const double dt = 0.05; // 20 fps
|
||||
while (!hasReachedEnd()) {
|
||||
traversePath(dt);
|
||||
}
|
||||
|
||||
// Compute speed factor to match the generated path length and duration, by
|
||||
// traversing the path and computing how much faster/slower it should be
|
||||
const int nSteps = 500;
|
||||
const double dt = (_duration / nSteps) > 0.01 ? (_duration / nSteps) : 0.01;
|
||||
|
||||
while (!hasReachedEnd()) {
|
||||
traversePath(dt);
|
||||
// We now know how long it took to traverse the path. Use that
|
||||
_speedFactorFromDuration = _progressedTime / *duration;
|
||||
}
|
||||
|
||||
_speedFactorFromDuration = _progressedTime / _duration;
|
||||
|
||||
// Reset playback variables
|
||||
_traveledDistance = 0.0;
|
||||
_progressedTime = 0.0;
|
||||
@@ -129,8 +129,6 @@ Waypoint Path::startPoint() const { return _start; }
|
||||
|
||||
Waypoint Path::endPoint() const { return _end; }
|
||||
|
||||
double Path::duration() const { return _duration; }
|
||||
|
||||
double Path::pathLength() const { return _curve->length(); }
|
||||
|
||||
std::vector<glm::dvec3> Path::controlPoints() const {
|
||||
@@ -219,11 +217,13 @@ glm::dquat Path::lookAtTargetsRotation(double t) const {
|
||||
}
|
||||
|
||||
// Handle up vector separately
|
||||
// @TODO (2021-09-06 emmbr) This actually does not interpolate the up vector of the
|
||||
// camera, but just the "hint" up vector for the lookAt. This leads to fast rolling
|
||||
// when the up vector gets close to the camera's forward vector. Should be improved
|
||||
// so any rolling is spread out over the entire motion instead
|
||||
double tUp = ghoul::sineEaseInOut(t);
|
||||
glm::dvec3 startUp = _start.rotation() * glm::dvec3(0.0, 1.0, 0.0);
|
||||
glm::dvec3 endUp = _end.rotation() * glm::dvec3(0.0, 1.0, 0.0);
|
||||
|
||||
double tUp = helpers::shiftAndScale(t, t1, t2);
|
||||
tUp = ghoul::sineEaseInOut(tUp);
|
||||
glm::dvec3 up = ghoul::interpolateLinear(tUp, startUp, endUp);
|
||||
|
||||
return ghoul::lookAtQuaternion(_curve->positionAt(t), lookAtPos, up);
|
||||
|
||||
@@ -44,94 +44,44 @@ namespace openspace::luascriptfunctions {
|
||||
|
||||
int isFlying(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::isFlying");
|
||||
|
||||
bool hasFinished = global::navigationHandler->pathNavigator().hasFinished();
|
||||
|
||||
ghoul::lua::push(L, !hasFinished);
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int continuePath(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::continuePath");
|
||||
|
||||
global::navigationHandler->pathNavigator().continuePath();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pausePath(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::pausePath");
|
||||
|
||||
global::navigationHandler->pathNavigator().pausePath();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stopPath(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::stopPath");
|
||||
|
||||
global::navigationHandler->pathNavigator().abortPath();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// All the goTo function has the same two optional input parameters at the end. The
|
||||
// purpose of this function is to handle these input parameters and add the result
|
||||
// to the dictionary specifying the instruction for a camera path.
|
||||
int handleOptionalGoToParameters(lua_State* L, const int startLocation,
|
||||
const int nArguments,
|
||||
ghoul::Dictionary& resultInstruction)
|
||||
{
|
||||
const bool firstIsNumber = (lua_isnumber(L, startLocation) != 0);
|
||||
const bool firstIsBool = (lua_isboolean(L, startLocation) != 0);
|
||||
|
||||
if (!(firstIsNumber || firstIsBool)) {
|
||||
const char* msg = lua_pushfstring(
|
||||
L,
|
||||
"%s or %s expected, got %s",
|
||||
lua_typename(L, LUA_TNUMBER),
|
||||
lua_typename(L, LUA_TBOOLEAN),
|
||||
luaL_typename(L, -1)
|
||||
);
|
||||
return ghoul::lua::luaError(
|
||||
L, fmt::format("bad argument #{} ({})", startLocation, msg)
|
||||
);
|
||||
}
|
||||
|
||||
int location = startLocation;
|
||||
|
||||
if (firstIsBool) {
|
||||
const bool useUpFromTarget = (lua_toboolean(L, location) == 1);
|
||||
resultInstruction.setValue("UseTargetUpDirection", useUpFromTarget);
|
||||
|
||||
if (nArguments > startLocation) {
|
||||
location++;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstIsNumber || nArguments > startLocation) {
|
||||
double duration = ghoul::lua::value<double>(L, location);
|
||||
if (duration <= Epsilon) {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(L, "Duration must be larger than zero.");
|
||||
}
|
||||
resultInstruction.setValue("Duration", duration);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int goTo(lua_State* L) {
|
||||
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 1, 3 }, "lua::goTo");
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 3 }, "lua::goTo");
|
||||
auto [nodeIdentifier, useUpFromTargetOrDuration, duration] = ghoul::lua::values<
|
||||
std::string, std::optional<std::variant<bool, double>>, std::optional<double>
|
||||
>(L);
|
||||
|
||||
if (useUpFromTargetOrDuration.has_value() &&
|
||||
std::holds_alternative<double>(*useUpFromTargetOrDuration)
|
||||
&& duration.has_value())
|
||||
{
|
||||
return ghoul::lua::luaError(L, "Duration cannot be specified twice");
|
||||
}
|
||||
|
||||
const std::string& nodeIdentifier = ghoul::lua::value<std::string>(L, 1);
|
||||
|
||||
if (!sceneGraphNode(nodeIdentifier)) {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(L, "Unknown node name: " + nodeIdentifier);
|
||||
}
|
||||
|
||||
@@ -139,12 +89,27 @@ int goTo(lua_State* L) {
|
||||
ghoul::Dictionary insDict;
|
||||
insDict.setValue("TargetType", "Node"s);
|
||||
insDict.setValue("Target", nodeIdentifier);
|
||||
|
||||
if (nArguments > 1) {
|
||||
int result = handleOptionalGoToParameters(L, 2, nArguments, insDict);
|
||||
if (result != 0) {
|
||||
return result; // An error occurred
|
||||
if (useUpFromTargetOrDuration.has_value()) {
|
||||
if (std::holds_alternative<bool>(*useUpFromTargetOrDuration)) {
|
||||
insDict.setValue(
|
||||
"UseTargetUpDirection",
|
||||
std::get<bool>(*useUpFromTargetOrDuration)
|
||||
);
|
||||
}
|
||||
else {
|
||||
double d = std::get<double>(*useUpFromTargetOrDuration);
|
||||
if (d <= Epsilon) {
|
||||
return ghoul::lua::luaError(L, "Duration must be larger than zero");
|
||||
}
|
||||
insDict.setValue("Duration", d);
|
||||
}
|
||||
}
|
||||
if (duration.has_value()) {
|
||||
double d = *duration;
|
||||
if (d <= Epsilon) {
|
||||
return ghoul::lua::luaError(L, "Duration must be larger than zero");
|
||||
}
|
||||
insDict.setValue("Duration", d);
|
||||
}
|
||||
|
||||
global::navigationHandler->pathNavigator().createPath(insDict);
|
||||
@@ -152,35 +117,48 @@ int goTo(lua_State* L) {
|
||||
if (global::navigationHandler->pathNavigator().hasCurrentPath()) {
|
||||
global::navigationHandler->pathNavigator().startPath();
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int goToHeight(lua_State* L) {
|
||||
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToHeight");
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToHeight");
|
||||
auto [nodeIdentifier, height, useUpFromTargetOrDuration, duration] =
|
||||
ghoul::lua::values<
|
||||
std::string, double, std::optional<std::variant<bool, double>>,
|
||||
std::optional<double>
|
||||
>(L);
|
||||
|
||||
const std::string& nodeIdentifier = ghoul::lua::value<std::string>(L, 1);
|
||||
|
||||
if (!sceneGraphNode(nodeIdentifier)) {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(L, "Unknown node name: " + nodeIdentifier);
|
||||
}
|
||||
|
||||
double height = ghoul::lua::value<double>(L, 2);
|
||||
|
||||
using namespace std::string_literals;
|
||||
ghoul::Dictionary insDict;
|
||||
insDict.setValue("TargetType", "Node"s);
|
||||
insDict.setValue("Target", nodeIdentifier);
|
||||
insDict.setValue("Height", height);
|
||||
|
||||
if (nArguments > 2) {
|
||||
int result = handleOptionalGoToParameters(L, 3, nArguments, insDict);
|
||||
if (result != 0) {
|
||||
return result; // An error occurred
|
||||
if (useUpFromTargetOrDuration.has_value()) {
|
||||
if (std::holds_alternative<bool>(*useUpFromTargetOrDuration)) {
|
||||
insDict.setValue(
|
||||
"UseTargetUpDirection",
|
||||
std::get<bool>(*useUpFromTargetOrDuration)
|
||||
);
|
||||
}
|
||||
else {
|
||||
double d = std::get<double>(*useUpFromTargetOrDuration);
|
||||
if (d <= Epsilon) {
|
||||
return ghoul::lua::luaError(L, "Duration must be larger than zero");
|
||||
}
|
||||
insDict.setValue("Duration", d);
|
||||
}
|
||||
}
|
||||
if (duration.has_value()) {
|
||||
double d = *duration;
|
||||
if (d <= Epsilon) {
|
||||
return ghoul::lua::luaError(L, "Duration must be larger than zero");
|
||||
}
|
||||
insDict.setValue("Duration", d);
|
||||
}
|
||||
|
||||
global::navigationHandler->pathNavigator().createPath(insDict);
|
||||
@@ -189,25 +167,17 @@ int goToHeight(lua_State* L) {
|
||||
global::navigationHandler->pathNavigator().startPath();
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int generatePath(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::generatePath");
|
||||
|
||||
ghoul::Dictionary dictionary;
|
||||
ghoul::lua::luaDictionaryFromState(L, dictionary);
|
||||
ghoul::Dictionary dictionary = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
global::navigationHandler->pathNavigator().createPath(dictionary);
|
||||
|
||||
if (global::navigationHandler->pathNavigator().hasCurrentPath()) {
|
||||
global::navigationHandler->pathNavigator().startPath();
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ ParallelConnection::ParallelConnection(std::unique_ptr<ghoul::io::TcpSocket> soc
|
||||
{}
|
||||
|
||||
bool ParallelConnection::isConnectedOrConnecting() const {
|
||||
return _socket->isConnected() || _socket->isConnecting();
|
||||
return _socket != nullptr && (_socket->isConnected() || _socket->isConnecting());
|
||||
}
|
||||
|
||||
void ParallelConnection::sendDataMessage(const DataMessage& dataMessage) {
|
||||
|
||||
@@ -26,45 +26,33 @@ namespace openspace::luascriptfunctions {
|
||||
|
||||
int connect(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::connect");
|
||||
|
||||
if (global::windowDelegate->isMaster()) {
|
||||
global::parallelPeer->connect();
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disconnect(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disconnect");
|
||||
|
||||
if (global::windowDelegate->isMaster()) {
|
||||
global::parallelPeer->connect();
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int requestHostship(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::requestHostship");
|
||||
|
||||
if (global::windowDelegate->isMaster()) {
|
||||
global::parallelPeer->requestHostship();
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int resignHostship(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::resignHostship");
|
||||
|
||||
if (global::windowDelegate->isMaster()) {
|
||||
global::parallelPeer->resignHostship();
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,70 +28,45 @@
|
||||
namespace openspace::luascriptfunctions {
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* addDashboardItem(table):
|
||||
*/
|
||||
* \ingroup LuaScripts
|
||||
* addDashboardItem(table):
|
||||
*/
|
||||
int addDashboardItem(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::addDashboardItem");
|
||||
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
const int type = lua_type(L, -1);
|
||||
if (type == LUA_TTABLE) {
|
||||
ghoul::Dictionary d;
|
||||
try {
|
||||
ghoul::lua::luaDictionaryFromState(L, d);
|
||||
}
|
||||
catch (const ghoul::lua::LuaFormatException& e) {
|
||||
LERRORC("addDashboardItem", e.what());
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
lua_settop(L, 0);
|
||||
|
||||
try {
|
||||
global::dashboard->addDashboardItem(DashboardItem::createFromDictionary(d));
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC("addDashboardItem", e.what());
|
||||
return ghoul::lua::luaError(L, "Error adding dashboard item");
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
try {
|
||||
global::dashboard->addDashboardItem(
|
||||
DashboardItem::createFromDictionary(std::move(d))
|
||||
);
|
||||
}
|
||||
else {
|
||||
return ghoul::lua::luaError(L, "Expected argument of type 'table'");
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC("addDashboardItem", e.what());
|
||||
return ghoul::lua::luaError(L, "Error adding dashboard item");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* removeDashboardItem(string):
|
||||
*/
|
||||
int removeDashboardItem(lua_State* L) {
|
||||
using ghoul::lua::errorLocation;
|
||||
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeDashbordItem");
|
||||
|
||||
std::string identifier = luaL_checkstring(L, -1);
|
||||
|
||||
global::dashboard->removeDashboardItem(identifier);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* removeDashboardItem(string):
|
||||
*/
|
||||
int removeDashboardItem(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeDashbordItem");
|
||||
const std::string identifier = ghoul::lua::value<std::string>(L);
|
||||
|
||||
global::dashboard->removeDashboardItem(identifier);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* removeDashboardItems():
|
||||
*/
|
||||
* \ingroup LuaScripts
|
||||
* removeDashboardItems():
|
||||
*/
|
||||
int clearDashboardItems(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::clearDashboardItems");
|
||||
|
||||
global::dashboard->clearDashboardItems();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -252,6 +252,18 @@ namespace {
|
||||
"Enable FXAA",
|
||||
"Enable FXAA"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo EnabledFontColorInfo = {
|
||||
"EnabledFontColor",
|
||||
"Enabled Font Color",
|
||||
"The font color used for enabled options."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo DisabledFontColorInfo = {
|
||||
"DisabledFontColor",
|
||||
"Disabled Font Color",
|
||||
"The font color used for disabled options."
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
@@ -295,6 +307,8 @@ RenderEngine::RenderEngine()
|
||||
glm::vec3(-glm::pi<float>()),
|
||||
glm::vec3(glm::pi<float>())
|
||||
)
|
||||
, _enabledFontColor(EnabledFontColorInfo, glm::vec4(0.2f, 0.75f, 0.2f, 1.f))
|
||||
, _disabledFontColor(DisabledFontColorInfo, glm::vec4(0.55f, 0.2f, 0.2f, 1.f))
|
||||
{
|
||||
addProperty(_showOverlayOnSlaves);
|
||||
addProperty(_showLog);
|
||||
@@ -380,6 +394,12 @@ RenderEngine::RenderEngine()
|
||||
addProperty(_screenSpaceRotation);
|
||||
addProperty(_masterRotation);
|
||||
addProperty(_disableMasterRendering);
|
||||
|
||||
_enabledFontColor.setViewOption(openspace::properties::Property::ViewOptions::Color);
|
||||
addProperty(_enabledFontColor);
|
||||
|
||||
_disabledFontColor.setViewOption(openspace::properties::Property::ViewOptions::Color);
|
||||
addProperty(_disabledFontColor);
|
||||
}
|
||||
|
||||
RenderEngine::~RenderEngine() {} // NOLINT
|
||||
@@ -1148,8 +1168,8 @@ void RenderEngine::renderCameraInformation() {
|
||||
return;
|
||||
}
|
||||
|
||||
const glm::vec4 EnabledColor = glm::vec4(0.2f, 0.75f, 0.2f, 1.f);
|
||||
const glm::vec4 DisabledColor = glm::vec4(0.55f, 0.2f, 0.2f, 1.f);
|
||||
const glm::vec4 EnabledColor = _enabledFontColor.value();
|
||||
const glm::vec4 DisabledColor = _disabledFontColor.value();
|
||||
|
||||
const glm::vec2 rotationBox = _fontCameraInfo->boundingBox("Rotation");
|
||||
|
||||
|
||||
@@ -28,50 +28,28 @@ namespace openspace::luascriptfunctions {
|
||||
|
||||
int addScreenSpaceRenderable(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::addScreenSpaceRenderable");
|
||||
|
||||
using ghoul::lua::errorLocation;
|
||||
|
||||
ghoul::Dictionary d;
|
||||
try {
|
||||
ghoul::lua::luaDictionaryFromState(L, d);
|
||||
lua_settop(L, 0);
|
||||
}
|
||||
catch (const ghoul::lua::LuaFormatException& e) {
|
||||
LERRORC("addScreenSpaceRenderable", e.what());
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
const ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
std::unique_ptr<ScreenSpaceRenderable> s =
|
||||
ScreenSpaceRenderable::createFromDictionary(d);
|
||||
ScreenSpaceRenderable::createFromDictionary(d);
|
||||
|
||||
global::renderEngine->addScreenSpaceRenderable(std::move(s));
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int removeScreenSpaceRenderable(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeScreenSpaceRenderable");
|
||||
const std::string name = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& name = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
global::renderEngine->removeScreenSpaceRenderable(name);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int takeScreenshot(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::takeScreenshot");
|
||||
|
||||
global::renderEngine->takeScreenshot();
|
||||
const unsigned int screenshotNumber = global::renderEngine->latestScreenshotNumber();
|
||||
|
||||
lua_pushinteger(L, screenshotNumber);
|
||||
ghoul::lua::push(L, screenshotNumber);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ namespace openspace::assetloader {
|
||||
* Adds a Lua function to be called upon asset initialization
|
||||
* Usage: void asset.onInitialize(function<void()> initFun)
|
||||
*/
|
||||
int onInitialize(lua_State* state) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(state, lua_upvalueindex(1)));
|
||||
int onInitialize(lua_State* L) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
return asset->loader()->onInitializeLua(asset);
|
||||
}
|
||||
|
||||
@@ -37,36 +37,28 @@ int onInitialize(lua_State* state) {
|
||||
* Adds a Lua function to be called upon asset deinitialization
|
||||
* Usage: void asset.onDeinitialize(function<void()> initFun)
|
||||
*/
|
||||
int onDeinitialize(lua_State* state) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(state, lua_upvalueindex(1)));
|
||||
int onDeinitialize(lua_State* L) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
return asset->loader()->onDeinitializeLua(asset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Lua function to be called when a dependency link is initialized
|
||||
* Usage: void asset.onInitialize(function<void()> initFun)
|
||||
*/
|
||||
int onInitializeDependency(lua_State* state) {
|
||||
Asset* dependant = reinterpret_cast<Asset*>(
|
||||
lua_touserdata(state, lua_upvalueindex(1))
|
||||
);
|
||||
Asset* dependency = reinterpret_cast<Asset*>(
|
||||
lua_touserdata(state, lua_upvalueindex(2))
|
||||
);
|
||||
* Adds a Lua function to be called when a dependency link is initialized
|
||||
* Usage: void asset.onInitialize(function<void()> initFun)
|
||||
*/
|
||||
int onInitializeDependency(lua_State* L) {
|
||||
Asset* dependant = reinterpret_cast<Asset*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
Asset* dependency = reinterpret_cast<Asset*>(lua_touserdata(L, lua_upvalueindex(2)));
|
||||
return dependant->loader()->onInitializeDependencyLua(dependant, dependency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Lua function to be called upon asset deinitialization
|
||||
* Usage: void asset.onDeinitialize(function<void()> initFun)
|
||||
*/
|
||||
int onDeinitializeDependency(lua_State* state) {
|
||||
Asset* dependant = reinterpret_cast<Asset*>(
|
||||
lua_touserdata(state, lua_upvalueindex(1))
|
||||
);
|
||||
Asset* dependency = reinterpret_cast<Asset*>(
|
||||
lua_touserdata(state, lua_upvalueindex(2))
|
||||
);
|
||||
* Adds a Lua function to be called upon asset deinitialization
|
||||
* Usage: void asset.onDeinitialize(function<void()> initFun)
|
||||
*/
|
||||
int onDeinitializeDependency(lua_State* L) {
|
||||
Asset* dependant = reinterpret_cast<Asset*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
Asset* dependency = reinterpret_cast<Asset*>(lua_touserdata(L, lua_upvalueindex(2)));
|
||||
return dependant->loader()->onDeinitializeDependencyLua(dependant, dependency);
|
||||
}
|
||||
|
||||
@@ -77,28 +69,28 @@ int onDeinitializeDependency(lua_State* state) {
|
||||
* Dependency: ...
|
||||
* Usage: {AssetTable, Dependency} = asset.import(string assetIdentifier)
|
||||
*/
|
||||
int require(lua_State* state) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(state, lua_upvalueindex(1)));
|
||||
int require(lua_State* L) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
return asset->loader()->requireLua(asset);
|
||||
}
|
||||
|
||||
int exists(lua_State* state) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(state, lua_upvalueindex(1)));
|
||||
int exists(lua_State* L) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
return asset->loader()->existsLua(asset);
|
||||
}
|
||||
|
||||
int localResource(lua_State* state) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(state, lua_upvalueindex(1)));
|
||||
int localResource(lua_State* L) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
return asset->loader()->localResourceLua(asset);
|
||||
}
|
||||
|
||||
int syncedResource(lua_State* state) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(state, lua_upvalueindex(1)));
|
||||
int syncedResource(lua_State* L) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
return asset->loader()->syncedResourceLua(asset);
|
||||
}
|
||||
|
||||
int exportAsset(lua_State* state) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(state, lua_upvalueindex(1)));
|
||||
int exportAsset(lua_State* L) {
|
||||
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
return asset->loader()->exportAssetLua(asset);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,17 +28,13 @@
|
||||
|
||||
namespace openspace::luascriptfunctions::asset {
|
||||
|
||||
int add(lua_State* state) {
|
||||
ghoul::lua::checkArgumentsAndThrow(state, 1, "lua::add");
|
||||
int add(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::add");
|
||||
|
||||
AssetManager* assetManager =
|
||||
reinterpret_cast<AssetManager*>(lua_touserdata(state, lua_upvalueindex(1)));
|
||||
|
||||
const std::string& assetName = ghoul::lua::value<std::string>(
|
||||
state,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
AssetManager* assetManager = reinterpret_cast<AssetManager*>(
|
||||
lua_touserdata(L, lua_upvalueindex(1))
|
||||
);
|
||||
const std::string assetName = ghoul::lua::value<std::string>(L);
|
||||
|
||||
if (global::renderEngine->scene()) {
|
||||
assetManager->add(assetName);
|
||||
@@ -49,36 +45,27 @@ int add(lua_State* state) {
|
||||
global::openSpaceEngine->scheduleLoadSingleAsset(assetName);
|
||||
}
|
||||
|
||||
|
||||
ghoul_assert(lua_gettop(state) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int remove(lua_State* state) {
|
||||
ghoul::lua::checkArgumentsAndThrow(state, 1, "lua::remove");
|
||||
int remove(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::remove");
|
||||
|
||||
AssetManager* assetManager =
|
||||
reinterpret_cast<AssetManager*>(lua_touserdata(state, lua_upvalueindex(1)));
|
||||
reinterpret_cast<AssetManager*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
const std::string assetName = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& assetName = ghoul::lua::value<std::string>(
|
||||
state,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
assetManager->remove(assetName);
|
||||
|
||||
ghoul_assert(lua_gettop(state) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int removeAll(lua_State* state) {
|
||||
ghoul::lua::checkArgumentsAndThrow(state, 0, "lua::removeAll");
|
||||
int removeAll(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::removeAll");
|
||||
|
||||
AssetManager* assetManager =
|
||||
reinterpret_cast<AssetManager*>(lua_touserdata(state, lua_upvalueindex(1)));
|
||||
reinterpret_cast<AssetManager*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
|
||||
assetManager->removeAll();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -499,12 +499,8 @@ void convertVersion10to11(nlohmann::json& profile) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This needs to be changed if there is another version for any of these types later
|
||||
using Action = Profile::Action;
|
||||
using Keybinding = Profile::Keybinding;
|
||||
|
||||
std::vector<Action> actions;
|
||||
std::vector<Keybinding> keybindings;
|
||||
std::vector<Profile::Action> actions;
|
||||
std::vector<Profile::Keybinding> keybindings;
|
||||
|
||||
std::vector<version10::Keybinding> kbs =
|
||||
profile.at("keybindings").get<std::vector<version10::Keybinding>>();
|
||||
@@ -512,7 +508,7 @@ void convertVersion10to11(nlohmann::json& profile) {
|
||||
version10::Keybinding& kb = kbs[i];
|
||||
std::string identifier = fmt::format("profile.keybind.{}", i);
|
||||
|
||||
Action action;
|
||||
Profile::Action action;
|
||||
action.identifier = identifier;
|
||||
action.documentation = std::move(kb.documentation);
|
||||
action.name = std::move(kb.name);
|
||||
@@ -521,7 +517,7 @@ void convertVersion10to11(nlohmann::json& profile) {
|
||||
action.script = std::move(kb.script);
|
||||
actions.push_back(std::move(action));
|
||||
|
||||
Keybinding keybinding;
|
||||
Profile::Keybinding keybinding;
|
||||
keybinding.key = kb.key;
|
||||
keybinding.action = identifier;
|
||||
keybindings.push_back(keybinding);
|
||||
|
||||
+40
-40
@@ -37,21 +37,19 @@ namespace openspace::luascriptfunctions {
|
||||
|
||||
int saveSettingsToProfile(lua_State* L) {
|
||||
if (!global::configuration->usingProfile) {
|
||||
return luaL_error(
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
"Program was not started with a profile, so cannot use this "
|
||||
"save-current-settings feature"
|
||||
);
|
||||
}
|
||||
|
||||
const int n = ghoul::lua::checkArgumentsAndThrow(
|
||||
L,
|
||||
{ 0, 2 },
|
||||
"lua::saveSettingsToProfile"
|
||||
);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 0, 2 }, "lua::saveSettingsToProfile");
|
||||
auto [saveFilePath, overwrite] =
|
||||
ghoul::lua::values<std::optional<std::string>, std::optional<bool>>(L);
|
||||
overwrite = overwrite.value_or(true);
|
||||
|
||||
std::string saveFilePath;
|
||||
if (n == 0) {
|
||||
if (!saveFilePath.has_value()) {
|
||||
std::time_t t = std::time(nullptr);
|
||||
std::tm* utcTime = std::gmtime(&t);
|
||||
ghoul_assert(utcTime, "Conversion to UTC failed");
|
||||
@@ -68,22 +66,27 @@ int saveSettingsToProfile(lua_State* L) {
|
||||
std::filesystem::path path = global::configuration->profile;
|
||||
path.replace_extension();
|
||||
std::string newFile = fmt::format("{}_{}", path.string(), time);
|
||||
std::string sourcePath = fmt::format("{}/{}.profile",
|
||||
absPath("${USER_PROFILES}").string(), global::configuration->profile);
|
||||
std::string destPath = fmt::format("{}/{}.profile",
|
||||
absPath("${PROFILES}").string(), global::configuration->profile);
|
||||
std::string sourcePath = fmt::format(
|
||||
"{}/{}.profile",
|
||||
absPath("${USER_PROFILES}").string(), global::configuration->profile
|
||||
);
|
||||
std::string destPath = fmt::format(
|
||||
"{}/{}.profile",
|
||||
absPath("${PROFILES}").string(), global::configuration->profile
|
||||
);
|
||||
if (!std::filesystem::is_regular_file(sourcePath)) {
|
||||
sourcePath = absPath("${USER_PROFILES}").string()
|
||||
+ '/' + global::configuration->profile + ".profile";
|
||||
sourcePath = fmt::format(
|
||||
"{}/{}.profile",
|
||||
absPath("${USER_PROFILES}").string(), global::configuration->profile
|
||||
);
|
||||
}
|
||||
LINFOC("Profile", fmt::format("Saving a copy of the old profile as {}", newFile));
|
||||
std::filesystem::copy(sourcePath, destPath);
|
||||
saveFilePath = global::configuration->profile;
|
||||
}
|
||||
else {
|
||||
saveFilePath = ghoul::lua::value<std::string>(L, 1);
|
||||
if (saveFilePath.empty()) {
|
||||
return luaL_error(L, "save filepath string is empty");
|
||||
if (saveFilePath->empty()) {
|
||||
return ghoul::lua::luaError(L, "Save filepath string is empty");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,32 +94,35 @@ int saveSettingsToProfile(lua_State* L) {
|
||||
std::string currentTime = std::string(global::timeManager->time().ISO8601());
|
||||
interaction::NavigationState navState = global::navigationHandler->navigationState();
|
||||
global::profile->saveCurrentSettingsToProfile(root, currentTime, navState);
|
||||
global::configuration->profile = saveFilePath;
|
||||
global::configuration->profile = *saveFilePath;
|
||||
|
||||
if (saveFilePath.find('/') != std::string::npos) {
|
||||
return luaL_error(L, "Profile filename must not contain path (/) elements");
|
||||
if (saveFilePath->find('/') != std::string::npos) {
|
||||
return ghoul::lua::luaError(L, "Profile filename must not contain (/) elements");
|
||||
}
|
||||
else if (saveFilePath.find(':') != std::string::npos) {
|
||||
return luaL_error(L, "Profile filename must not contain path (:) elements");
|
||||
else if (saveFilePath->find(':') != std::string::npos) {
|
||||
return ghoul::lua::luaError(L, "Profile filename must not contain (:) elements");
|
||||
}
|
||||
else if (saveFilePath.find('.') != std::string::npos) {
|
||||
return luaL_error(L, "Only provide the filename to save without file extension");
|
||||
else if (saveFilePath->find('.') != std::string::npos) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
"Only provide the filename to save without file extension"
|
||||
);
|
||||
}
|
||||
|
||||
std::string absFilename = fmt::format("{}/{}.profile",
|
||||
absPath("${PROFILES}").string(), saveFilePath);
|
||||
std::string absFilename = fmt::format(
|
||||
"{}/{}.profile", absPath("${PROFILES}").string(), *saveFilePath
|
||||
);
|
||||
if (!std::filesystem::is_regular_file(absFilename)) {
|
||||
absFilename = absPath("${USER_PROFILES}/" + saveFilePath + ".profile").string();
|
||||
absFilename = absPath("${USER_PROFILES}/" + *saveFilePath + ".profile").string();
|
||||
}
|
||||
const bool overwrite = (n == 2) ? ghoul::lua::value<bool>(L, 2) : true;
|
||||
|
||||
if (std::filesystem::is_regular_file(absFilename) && !overwrite) {
|
||||
return luaL_error(
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format(
|
||||
"Unable to save profile '{}'. File of same name already exists",
|
||||
absFilename
|
||||
).c_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -126,11 +132,11 @@ int saveSettingsToProfile(lua_State* L) {
|
||||
outFile.open(absFilename, std::ofstream::out);
|
||||
}
|
||||
catch (const std::ofstream::failure& e) {
|
||||
return luaL_error(
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format(
|
||||
"Exception opening profile file for write: {} ({})", absFilename, e.what()
|
||||
).c_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -138,17 +144,11 @@ int saveSettingsToProfile(lua_State* L) {
|
||||
outFile << global::profile->serialize();
|
||||
}
|
||||
catch (const std::ofstream::failure& e) {
|
||||
return luaL_error(
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format(
|
||||
"Data write error to file: {} ({})", absFilename, e.what()
|
||||
).c_str()
|
||||
fmt::format("Data write error to file: {} ({})", absFilename, e.what())
|
||||
);
|
||||
}
|
||||
|
||||
outFile.close();
|
||||
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+74
-150
@@ -38,7 +38,7 @@ namespace {
|
||||
|
||||
template <class T>
|
||||
properties::PropertyOwner* findPropertyOwnerWithMatchingGroupTag(T* prop,
|
||||
const std::string& tagToMatch)
|
||||
const std::string& tagToMatch)
|
||||
{
|
||||
properties::PropertyOwner* tagMatchOwner = nullptr;
|
||||
properties::PropertyOwner* owner = prop->owner();
|
||||
@@ -62,10 +62,9 @@ properties::PropertyOwner* findPropertyOwnerWithMatchingGroupTag(T* prop,
|
||||
}
|
||||
|
||||
void applyRegularExpression(lua_State* L, const std::string& regex,
|
||||
const std::vector<properties::Property*>& properties,
|
||||
double interpolationDuration,
|
||||
const std::string& groupName,
|
||||
ghoul::EasingFunction easingFunction)
|
||||
const std::vector<properties::Property*>& properties,
|
||||
double interpolationDuration, const std::string& groupName,
|
||||
ghoul::EasingFunction easingFunction)
|
||||
{
|
||||
using ghoul::lua::errorLocation;
|
||||
using ghoul::lua::luaTypeToString;
|
||||
@@ -76,8 +75,8 @@ void applyRegularExpression(lua_State* L, const std::string& regex,
|
||||
const int type = lua_type(L, -1);
|
||||
|
||||
// Extract the property and node name to be searched for from regex
|
||||
std::string propertyName = "";
|
||||
std::string nodeName = "";
|
||||
std::string propertyName;
|
||||
std::string nodeName;
|
||||
size_t wildPos = regex.find_first_of("*");
|
||||
if (wildPos != std::string::npos) {
|
||||
nodeName = regex.substr(0, wildPos);
|
||||
@@ -88,8 +87,8 @@ void applyRegularExpression(lua_State* L, const std::string& regex,
|
||||
LERRORC(
|
||||
"applyRegularExpression",
|
||||
fmt::format(
|
||||
"Malformed regular expression: '{}': "
|
||||
"Empty both before and after '*'", regex
|
||||
"Malformed regular expression: '{}': Empty both before and after '*'",
|
||||
regex
|
||||
)
|
||||
);
|
||||
return;
|
||||
@@ -100,8 +99,8 @@ void applyRegularExpression(lua_State* L, const std::string& regex,
|
||||
LERRORC(
|
||||
"applyRegularExpression",
|
||||
fmt::format(
|
||||
"Malformed regular expression: '{}': "
|
||||
"Currently only one '*' is supported", regex
|
||||
"Malformed regular expression: '{}': Currently only one '*' is "
|
||||
"supported", regex
|
||||
)
|
||||
);
|
||||
return;
|
||||
@@ -120,7 +119,7 @@ void applyRegularExpression(lua_State* L, const std::string& regex,
|
||||
bool foundMatching = false;
|
||||
for (properties::Property* prop : properties) {
|
||||
// Check the regular expression for all properties
|
||||
const std::string& id = prop->fullyQualifiedIdentifier();
|
||||
const std::string id = prop->fullyQualifiedIdentifier();
|
||||
|
||||
if (isLiteral && id != propertyName) {
|
||||
continue;
|
||||
@@ -141,10 +140,7 @@ void applyRegularExpression(lua_State* L, const std::string& regex,
|
||||
// Check tag
|
||||
if (isGroupMode) {
|
||||
properties::PropertyOwner* matchingTaggedOwner =
|
||||
findPropertyOwnerWithMatchingGroupTag(
|
||||
prop,
|
||||
groupName
|
||||
);
|
||||
findPropertyOwnerWithMatchingGroupTag(prop, groupName);
|
||||
if (!matchingTaggedOwner) {
|
||||
continue;
|
||||
}
|
||||
@@ -157,14 +153,10 @@ void applyRegularExpression(lua_State* L, const std::string& regex,
|
||||
else if (!nodeName.empty()) {
|
||||
size_t nodePos = id.find(nodeName);
|
||||
if (nodePos != std::string::npos) {
|
||||
|
||||
// Check tag
|
||||
if (isGroupMode) {
|
||||
properties::PropertyOwner* matchingTaggedOwner =
|
||||
findPropertyOwnerWithMatchingGroupTag(
|
||||
prop,
|
||||
groupName
|
||||
);
|
||||
findPropertyOwnerWithMatchingGroupTag(prop, groupName);
|
||||
if (!matchingTaggedOwner) {
|
||||
continue;
|
||||
}
|
||||
@@ -184,12 +176,10 @@ void applyRegularExpression(lua_State* L, const std::string& regex,
|
||||
LERRORC(
|
||||
"property_setValue",
|
||||
fmt::format(
|
||||
"{}: Property '{}' does not accept input of type '{}'. "
|
||||
"Requested type: '{}'",
|
||||
errorLocation(L),
|
||||
prop->fullyQualifiedIdentifier(),
|
||||
luaTypeToString(type),
|
||||
luaTypeToString(prop->typeLua())
|
||||
"{}: Property '{}' does not accept input of type '{}'. Requested "
|
||||
"type: '{}'",
|
||||
errorLocation(L), prop->fullyQualifiedIdentifier(),
|
||||
luaTypeToString(type), luaTypeToString(prop->typeLua())
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -220,9 +210,7 @@ void applyRegularExpression(lua_State* L, const std::string& regex,
|
||||
LERRORC(
|
||||
"property_setValue",
|
||||
fmt::format(
|
||||
"{}: No property matched the requested URI '{}'",
|
||||
errorLocation(L),
|
||||
regex
|
||||
"{}: No property matched the requested URI '{}'", errorLocation(L), regex
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -231,7 +219,7 @@ void applyRegularExpression(lua_State* L, const std::string& regex,
|
||||
// Checks to see if URI contains a group tag (with { } around the first term). If so,
|
||||
// returns true and sets groupName with the tag
|
||||
bool doesUriContainGroupTag(const std::string& command, std::string& groupName) {
|
||||
std::string name = command.substr(0, command.find_first_of("."));
|
||||
const std::string name = command.substr(0, command.find_first_of("."));
|
||||
if (name.front() == '{' && name.back() == '}') {
|
||||
groupName = name.substr(1, name.length() - 2);
|
||||
return true;
|
||||
@@ -251,8 +239,8 @@ std::string removeGroupNameFromUri(const std::string& uri) {
|
||||
namespace openspace::luascriptfunctions {
|
||||
|
||||
int setPropertyCall_single(properties::Property& prop, const std::string& uri,
|
||||
lua_State* L, double duration,
|
||||
ghoul::EasingFunction easingFunction)
|
||||
lua_State* L, double duration,
|
||||
ghoul::EasingFunction easingFunction)
|
||||
{
|
||||
using ghoul::lua::errorLocation;
|
||||
using ghoul::lua::luaTypeToString;
|
||||
@@ -264,9 +252,7 @@ int setPropertyCall_single(properties::Property& prop, const std::string& uri,
|
||||
fmt::format(
|
||||
"{}: Property '{}' does not accept input of type '{}'. "
|
||||
"Requested type: '{}'",
|
||||
errorLocation(L),
|
||||
uri,
|
||||
luaTypeToString(type),
|
||||
errorLocation(L), uri, luaTypeToString(type),
|
||||
luaTypeToString(prop.typeLua())
|
||||
)
|
||||
);
|
||||
@@ -304,37 +290,39 @@ int setPropertyCall_single(properties::Property& prop, const std::string& uri,
|
||||
*/
|
||||
|
||||
int property_setValue(lua_State* L) {
|
||||
using ghoul::lua::errorLocation;
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 2, 5 }, "lua::property_setValue");
|
||||
defer { lua_settop(L, 0); };
|
||||
|
||||
std::string uriOrRegex = ghoul::lua::value<std::string>(L, 1);
|
||||
std::string uriOrRegex =
|
||||
ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::No);
|
||||
std::string optimization;
|
||||
double interpolationDuration = 0.0;
|
||||
std::string easingMethodName;
|
||||
ghoul::EasingFunction easingMethod = ghoul::EasingFunction::Linear;
|
||||
|
||||
if (lua_gettop(L) >= 3) {
|
||||
if (lua_type(L, 3) == LUA_TNUMBER) {
|
||||
interpolationDuration = ghoul::lua::value<double>(L, 3);
|
||||
if (ghoul::lua::hasValue<double>(L, 3)) {
|
||||
interpolationDuration =
|
||||
ghoul::lua::value<double>(L, 3, ghoul::lua::PopValue::No);
|
||||
}
|
||||
else {
|
||||
optimization = ghoul::lua::value<std::string>(L, 3);
|
||||
optimization =
|
||||
ghoul::lua::value<std::string>(L, 3, ghoul::lua::PopValue::No);
|
||||
}
|
||||
|
||||
if (lua_gettop(L) >= 4) {
|
||||
if (lua_type(L, 4) == LUA_TNUMBER) {
|
||||
interpolationDuration = ghoul::lua::value<double>(L, 4);
|
||||
if (ghoul::lua::hasValue<double>(L, 4)) {
|
||||
interpolationDuration =
|
||||
ghoul::lua::value<double>(L, 4, ghoul::lua::PopValue::No);
|
||||
}
|
||||
else {
|
||||
easingMethodName = ghoul::lua::value<std::string>(L, 4);
|
||||
easingMethodName =
|
||||
ghoul::lua::value<std::string>(L, 4, ghoul::lua::PopValue::No);
|
||||
}
|
||||
}
|
||||
|
||||
if (lua_gettop(L) == 5) {
|
||||
optimization = ghoul::lua::value<std::string>(L, 5);
|
||||
optimization = ghoul::lua::value<std::string>(L, 5, ghoul::lua::PopValue::No);
|
||||
}
|
||||
|
||||
// Later functions expect the value to be at the last position on the stack
|
||||
@@ -349,7 +337,7 @@ int property_setValue(lua_State* L) {
|
||||
}
|
||||
|
||||
if (!easingMethodName.empty()) {
|
||||
bool correctName = ghoul::isValidEasingFunctionName(easingMethodName.c_str());
|
||||
bool correctName = ghoul::isValidEasingFunctionName(easingMethodName);
|
||||
if (!correctName) {
|
||||
LWARNINGC(
|
||||
"property_setValue",
|
||||
@@ -357,7 +345,7 @@ int property_setValue(lua_State* L) {
|
||||
);
|
||||
}
|
||||
else {
|
||||
easingMethod = ghoul::easingFunctionFromName(easingMethodName.c_str());
|
||||
easingMethod = ghoul::easingFunctionFromName(easingMethodName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,8 +383,7 @@ int property_setValue(lua_State* L) {
|
||||
"property_setValue",
|
||||
fmt::format(
|
||||
"{}: Property with URI '{}' was not found",
|
||||
errorLocation(L),
|
||||
uriOrRegex
|
||||
ghoul::lua::errorLocation(L), uriOrRegex
|
||||
)
|
||||
);
|
||||
return 0;
|
||||
@@ -414,8 +401,7 @@ int property_setValue(lua_State* L) {
|
||||
"lua::property_setGroup",
|
||||
fmt::format(
|
||||
"{}: Unexpected optimization '{}'",
|
||||
errorLocation(L),
|
||||
optimization
|
||||
ghoul::lua::errorLocation(L), optimization
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -442,14 +428,9 @@ int property_setValueSingle(lua_State* L) {
|
||||
*/
|
||||
int property_hasProperty(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::property_hasProperty");
|
||||
const std::string uri = ghoul::lua::value<std::string>(L);
|
||||
|
||||
std::string uri = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
|
||||
openspace::properties::Property* prop = property(uri);
|
||||
properties::Property* prop = property(uri);
|
||||
ghoul::lua::push(L, prop != nullptr);
|
||||
return 1;
|
||||
}
|
||||
@@ -462,44 +443,33 @@ int property_hasProperty(lua_State* L) {
|
||||
*/
|
||||
int property_getValue(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::property_getValue");
|
||||
const std::string uri = ghoul::lua::value<std::string>(L);
|
||||
|
||||
std::string uri = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
|
||||
openspace::properties::Property* prop = property(uri);
|
||||
properties::Property* prop = property(uri);
|
||||
if (!prop) {
|
||||
LERRORC(
|
||||
"property_getValue",
|
||||
fmt::format(
|
||||
"{}: Property with URI '{}' was not found",
|
||||
ghoul::lua::errorLocation(L),
|
||||
uri
|
||||
ghoul::lua::errorLocation(L), uri
|
||||
)
|
||||
);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
prop->getLuaValue(L);
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* getProperty
|
||||
* Returns a list of property identifiers that match the passed regular expression
|
||||
*/
|
||||
* \ingroup LuaScripts
|
||||
* getProperty
|
||||
* Returns a list of property identifiers that match the passed regular expression
|
||||
*/
|
||||
int property_getProperty(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::property_getProperty");
|
||||
|
||||
std::string regex = ghoul::lua::value<std::string>(L, 1);
|
||||
lua_pop(L, 1);
|
||||
std::string regex = ghoul::lua::value<std::string>(L);
|
||||
|
||||
std::string groupName;
|
||||
if (doesUriContainGroupTag(regex, groupName)) {
|
||||
@@ -509,8 +479,8 @@ int property_getProperty(lua_State* L) {
|
||||
|
||||
// Extract the property and node name to be searched for from regex
|
||||
bool isLiteral = false;
|
||||
std::string propertyName = "";
|
||||
std::string nodeName = "";
|
||||
std::string propertyName;
|
||||
std::string nodeName;
|
||||
size_t wildPos = regex.find_first_of("*");
|
||||
if (wildPos != std::string::npos) {
|
||||
nodeName = regex.substr(0, wildPos);
|
||||
@@ -521,8 +491,8 @@ int property_getProperty(lua_State* L) {
|
||||
LERRORC(
|
||||
"property_getProperty",
|
||||
fmt::format(
|
||||
"Malformed regular expression: '{}': "
|
||||
"Empty both before and after '*'", regex
|
||||
"Malformed regular expression: '{}': Empty both before and after '*'",
|
||||
regex
|
||||
)
|
||||
);
|
||||
return 0;
|
||||
@@ -574,10 +544,7 @@ int property_getProperty(lua_State* L) {
|
||||
// Check tag
|
||||
if (!groupName.empty()) {
|
||||
properties::PropertyOwner* matchingTaggedOwner =
|
||||
findPropertyOwnerWithMatchingGroupTag(
|
||||
prop,
|
||||
groupName
|
||||
);
|
||||
findPropertyOwnerWithMatchingGroupTag(prop, groupName);
|
||||
if (!matchingTaggedOwner) {
|
||||
continue;
|
||||
}
|
||||
@@ -594,10 +561,7 @@ int property_getProperty(lua_State* L) {
|
||||
// Check tag
|
||||
if (!groupName.empty()) {
|
||||
properties::PropertyOwner* matchingTaggedOwner =
|
||||
findPropertyOwnerWithMatchingGroupTag(
|
||||
prop,
|
||||
groupName
|
||||
);
|
||||
findPropertyOwnerWithMatchingGroupTag(prop, groupName);
|
||||
if (!matchingTaggedOwner) {
|
||||
continue;
|
||||
}
|
||||
@@ -618,35 +582,24 @@ int property_getProperty(lua_State* L) {
|
||||
lua_newtable(L);
|
||||
int number = 1;
|
||||
for (const std::string& s : res) {
|
||||
lua_pushstring(L, s.c_str());
|
||||
ghoul::lua::push(L, s);
|
||||
lua_rawseti(L, -2, number);
|
||||
++number;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int loadScene(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadScene");
|
||||
std::string sceneFile = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& sceneFile = ghoul::lua::value<std::string>(L, 1);
|
||||
global::openSpaceEngine->scheduleLoadSingleAsset(sceneFile);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
global::openSpaceEngine->scheduleLoadSingleAsset(std::move(sceneFile));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addSceneGraphNode(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::addSceneGraphNode");
|
||||
|
||||
ghoul::Dictionary d;
|
||||
try {
|
||||
ghoul::lua::luaDictionaryFromState(L, d);
|
||||
}
|
||||
catch (const ghoul::lua::LuaFormatException& e) {
|
||||
LERRORC("addSceneGraphNode", e.what());
|
||||
return ghoul::lua::luaError(L, "Error loading dictionary from lua state");
|
||||
}
|
||||
const ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
try {
|
||||
SceneGraphNode* node = global::renderEngine->scene()->loadNode(d);
|
||||
@@ -658,7 +611,7 @@ int addSceneGraphNode(lua_State* L) {
|
||||
global::renderEngine->scene()->initializeNode(node);
|
||||
}
|
||||
catch (const documentation::SpecificationError& e) {
|
||||
std::string cat =
|
||||
std::string cat =
|
||||
d.hasValue<std::string>("Identifier") ?
|
||||
d.value<std::string>("Identifier") :
|
||||
"Scene";
|
||||
@@ -675,16 +628,12 @@ int addSceneGraphNode(lua_State* L) {
|
||||
fmt::format("Error loading scene graph node: {}", e.what())
|
||||
);
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int removeSceneGraphNode(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeSceneGraphNode");
|
||||
|
||||
std::string name = ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::Yes);
|
||||
const std::string name = ghoul::lua::value<std::string>(L);
|
||||
|
||||
SceneGraphNode* foundNode = sceneGraphNode(name);
|
||||
if (!foundNode) {
|
||||
@@ -733,23 +682,20 @@ int removeSceneGraphNode(lua_State* L) {
|
||||
};
|
||||
|
||||
removeNode(foundNode);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int removeSceneGraphNodesFromRegex(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeSceneGraphNodesFromRegex");
|
||||
|
||||
std::string name = ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::Yes);
|
||||
const std::string name = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::vector<SceneGraphNode*>& nodes =
|
||||
global::renderEngine->scene()->allSceneGraphNodes();
|
||||
|
||||
// Extract the property and node name to be searched for from name
|
||||
bool isLiteral = false;
|
||||
std::string propertyName = "";
|
||||
std::string nodeName = "";
|
||||
std::string propertyName;
|
||||
std::string nodeName;
|
||||
size_t wildPos = name.find_first_of("*");
|
||||
if (wildPos != std::string::npos) {
|
||||
nodeName = name.substr(0, wildPos);
|
||||
@@ -760,8 +706,8 @@ int removeSceneGraphNodesFromRegex(lua_State* L) {
|
||||
LERRORC(
|
||||
"removeSceneGraphNodesFromRegex",
|
||||
fmt::format(
|
||||
"Malformed regular expression: '{}': "
|
||||
"Empty both before and after '*'", name
|
||||
"Malformed regular expression: '{}': Empty both before and after '*'",
|
||||
name
|
||||
)
|
||||
);
|
||||
return 0;
|
||||
@@ -827,8 +773,7 @@ int removeSceneGraphNodesFromRegex(lua_State* L) {
|
||||
SceneGraphNode* parent = node->parent();
|
||||
if (!parent) {
|
||||
LERRORC(
|
||||
"removeSceneGraphNodesFromRegex",
|
||||
fmt::format("Cannot remove root node")
|
||||
"removeSceneGraphNodesFromRegex", fmt::format("Cannot remove root node")
|
||||
);
|
||||
}
|
||||
else {
|
||||
@@ -848,8 +793,7 @@ int removeSceneGraphNodesFromRegex(lua_State* L) {
|
||||
std::function<void(SceneGraphNode*, std::vector<SceneGraphNode*>&)> markNode =
|
||||
[&markNode](SceneGraphNode* node, std::vector<SceneGraphNode*>& marked)
|
||||
{
|
||||
std::vector<SceneGraphNode*> children = node->children();
|
||||
for (SceneGraphNode* child : children) {
|
||||
for (SceneGraphNode* child : node->children()) {
|
||||
markNode(child, marked);
|
||||
}
|
||||
|
||||
@@ -899,48 +843,33 @@ int removeSceneGraphNodesFromRegex(lua_State* L) {
|
||||
removeNode(markedList[0]);
|
||||
}
|
||||
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hasSceneGraphNode(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::hasSceneGraphNode");
|
||||
const std::string nodeName = ghoul::lua::value<std::string>(L);
|
||||
|
||||
std::string nodeName = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(nodeName);
|
||||
|
||||
ghoul::lua::push(L, node != nullptr);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int addInterestingTime(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addInterestingTime");
|
||||
|
||||
std::string name = ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::No);
|
||||
std::string time = ghoul::lua::value<std::string>(L, 2, ghoul::lua::PopValue::No);
|
||||
lua_pop(L, 2);
|
||||
auto [name, time] = ghoul::lua::values<std::string, std::string>(L);
|
||||
|
||||
global::renderEngine->scene()->addInterestingTime(
|
||||
{ std::move(name), std::move(time) }
|
||||
);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int worldPosition(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::worldPosition");
|
||||
const std::string identifier = ghoul::lua::value<std::string>(L);
|
||||
|
||||
std::string identifier = ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::Yes);
|
||||
SceneGraphNode* node = sceneGraphNode(identifier);
|
||||
|
||||
if (!node) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
@@ -949,18 +878,15 @@ int worldPosition(lua_State* L) {
|
||||
}
|
||||
|
||||
glm::dvec3 pos = node->worldPosition();
|
||||
ghoul::lua::push(L, pos);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
ghoul::lua::push(L, std::move(pos));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int worldRotation(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::worldRotation");
|
||||
std::string identifier = ghoul::lua::value<std::string>(L);
|
||||
|
||||
std::string identifier = ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::Yes);
|
||||
SceneGraphNode* node = sceneGraphNode(identifier);
|
||||
|
||||
if (!node) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
@@ -969,9 +895,7 @@ int worldRotation(lua_State* L) {
|
||||
}
|
||||
|
||||
glm::dmat3 rot = node->worldRotationMatrix();
|
||||
ghoul::lua::push(L, rot);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
ghoul::lua::push(L, std::move(rot));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,6 @@ int printInternal(ghoul::logging::LogLevel level, lua_State* L) {
|
||||
log(level, "print", ghoul::lua::luaValueToString(L, i));
|
||||
}
|
||||
lua_pop(L, nArguments);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -114,16 +112,9 @@ int printFatal(lua_State* L) {
|
||||
*/
|
||||
int absolutePath(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::absolutePath");
|
||||
|
||||
const std::string& path = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
const std::string path = ghoul::lua::value<std::string>(L);
|
||||
|
||||
ghoul::lua::push(L, absPath(path).string());
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -135,18 +126,13 @@ int absolutePath(lua_State* L) {
|
||||
*/
|
||||
int setPathToken(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::setPathToken");
|
||||
|
||||
std::string pathToken = ghoul::lua::value<std::string>(L, 1);
|
||||
std::string path = ghoul::lua::value<std::string>(L, 2);
|
||||
auto [pathToken, path] = ghoul::lua::values<std::string, std::string>(L);
|
||||
|
||||
FileSys.registerPathToken(
|
||||
std::move(pathToken),
|
||||
std::move(path),
|
||||
ghoul::filesystem::FileSystem::Override::Yes
|
||||
);
|
||||
|
||||
lua_pop(L, 2);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -157,17 +143,10 @@ int setPathToken(lua_State* L) {
|
||||
*/
|
||||
int fileExists(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::fileExists");
|
||||
std::string file = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& file = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
const bool e = std::filesystem::is_regular_file(absPath(file));
|
||||
|
||||
const bool e = std::filesystem::is_regular_file(absPath(std::move(file)));
|
||||
ghoul::lua::push(L, e);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -178,15 +157,11 @@ int fileExists(lua_State* L) {
|
||||
*/
|
||||
int readFile(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::readFile");
|
||||
const std::string file = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& file = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
std::filesystem::path p = absPath(file);
|
||||
if (!std::filesystem::is_regular_file(p)) {
|
||||
return ghoul::lua::luaError(L, fmt::format("Could not open file {}", file));
|
||||
return ghoul::lua::luaError(L, fmt::format("Could not open file '{}'", file));
|
||||
}
|
||||
|
||||
std::ifstream f(p);
|
||||
@@ -204,26 +179,19 @@ int readFile(lua_State* L) {
|
||||
*/
|
||||
int directoryExists(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::directoryExists");
|
||||
std::string file = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& file = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
const bool e = std::filesystem::is_directory(absPath(file));
|
||||
|
||||
const bool e = std::filesystem::is_directory(absPath(std::move(file)));
|
||||
ghoul::lua::push(L, e);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int walkCommon(lua_State* L, std::function<bool(const std::filesystem::path&)> filter) {
|
||||
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 1, 3 }, "lua::walkCommon");
|
||||
|
||||
const std::string path = ghoul::lua::value<std::string>(L, 1);
|
||||
const bool recursive = nArguments >= 2 ? ghoul::lua::value<bool>(L, 2) : false;
|
||||
const bool sorted = nArguments == 3 ? ghoul::lua::value<bool>(L, 3) : false;
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 3 }, "lua::walkCommon");
|
||||
auto [path, recursive, sorted] =
|
||||
ghoul::lua::values<std::string, std::optional<bool>, std::optional<bool>>(L);
|
||||
recursive = recursive.value_or(false);
|
||||
sorted = sorted.value_or(false);
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
std::vector<fs::directory_entry> result;
|
||||
@@ -242,16 +210,14 @@ int walkCommon(lua_State* L, std::function<bool(const std::filesystem::path&)> f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sorted) {
|
||||
std::sort(result.begin(), result.end());
|
||||
}
|
||||
}
|
||||
if (sorted) {
|
||||
std::sort(result.begin(), result.end());
|
||||
}
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(result.size()); ++i) {
|
||||
lua_pushstring(L, result[i].path().string().c_str());
|
||||
ghoul::lua::push(L, result[i].path().string());
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
return 1;
|
||||
@@ -289,14 +255,14 @@ int walkDirectoryFiles(lua_State* L) {
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* walkDirectory(string, bool, bool):
|
||||
* Walks a directory and returns the subfolders of the directory as absolute paths. The
|
||||
* first argument is the path of the directory that should be walked, the second argument
|
||||
* determines if the walk is recursive and will continue in contained directories. The
|
||||
* default value for this parameter is "false". The third argument determines whether the
|
||||
* table that is returned is sorted. The default value for this parameter is "false".
|
||||
*/
|
||||
* \ingroup LuaScripts
|
||||
* walkDirectory(string, bool, bool):
|
||||
* Walks a directory and returns the subfolders of the directory as absolute paths. The
|
||||
* first argument is the path of the directory that should be walked, the second argument
|
||||
* determines if the walk is recursive and will continue in contained directories. The
|
||||
* default value for this parameter is "false". The third argument determines whether the
|
||||
* table that is returned is sorted. The default value for this parameter is "false".
|
||||
*/
|
||||
int walkDirectoryFolder(lua_State* L) {
|
||||
namespace fs = std::filesystem;
|
||||
return walkCommon(L, [](const fs::path& p) { return fs::is_directory(p); });
|
||||
@@ -311,13 +277,10 @@ int walkDirectoryFolder(lua_State* L) {
|
||||
*/
|
||||
int directoryForPath(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::directoryForPath");
|
||||
std::string file = ghoul::lua::value<std::string>(L);
|
||||
|
||||
std::string file = ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::Yes);
|
||||
std::string path = std::filesystem::path(std::move(file)).parent_path().string();
|
||||
|
||||
ghoul::lua::push(L, path);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
ghoul::lua::push(L, std::move(path));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -330,33 +293,19 @@ int directoryForPath(lua_State* L) {
|
||||
* is finished.
|
||||
*/
|
||||
int unzipFile(lua_State* L) {
|
||||
const int nArguments = ghoul::lua::checkArgumentsAndThrow(
|
||||
L,
|
||||
{ 2, 3 },
|
||||
"lua::unzipFile"
|
||||
);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 2, 3 }, "lua::unzipFile");
|
||||
auto [source, dest, deleteSource] =
|
||||
ghoul::lua::values<std::string, std::string, std::optional<bool>>(L);
|
||||
source = absPath(source).string();
|
||||
dest = absPath(dest).string();
|
||||
deleteSource = deleteSource.value_or(false);
|
||||
|
||||
std::filesystem::path source = absPath(
|
||||
ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::No)
|
||||
);
|
||||
std::filesystem::path dest = absPath(
|
||||
ghoul::lua::value<std::string>(L, 2, ghoul::lua::PopValue::No)
|
||||
);
|
||||
|
||||
bool deleteSource = false;
|
||||
if (nArguments == 3) {
|
||||
deleteSource = ghoul::lua::value<bool>(L, 3, ghoul::lua::PopValue::No);
|
||||
}
|
||||
|
||||
auto onExtractEntry = [](const char*, void*) { return 0; };
|
||||
int arg = 2;
|
||||
zip_extract(source.string().c_str(), dest.string().c_str(), onExtractEntry, &arg);
|
||||
zip_extract(source.c_str(), dest.c_str(), [](const char*, void*) { return 0; }, &arg);
|
||||
|
||||
if (deleteSource && std::filesystem::is_regular_file(source)) {
|
||||
std::filesystem::remove(source);
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -372,7 +321,7 @@ int saveLastChangeToProfile(lua_State* L) {
|
||||
std::string actualLastLine;
|
||||
std::string lastLine;
|
||||
std::string line;
|
||||
//add check for log file
|
||||
// add check for log file
|
||||
if (!logfile.good()) {
|
||||
ghoul::lua::push(L, fmt::format("Could not open scriptlog {}", logFilePath));
|
||||
printInternal(ghoul::logging::LogLevel::Error, L);
|
||||
|
||||
@@ -28,12 +28,8 @@ namespace openspace::luascriptfunctions {
|
||||
|
||||
int loadFile(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadFile");
|
||||
const std::string& fileName = ghoul::lua::value<std::string>(L);
|
||||
|
||||
const std::string& fileName = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
if (fileName.empty()) {
|
||||
return ghoul::lua::luaError(L, "filepath string is empty");
|
||||
}
|
||||
@@ -56,78 +52,48 @@ int loadFile(lua_State* L) {
|
||||
}
|
||||
|
||||
global::scriptScheduler->loadScripts(scripts);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int loadScheduledScript(lua_State* L) {
|
||||
int nArguments = ghoul::lua::checkArgumentsAndThrow(
|
||||
L,
|
||||
{ 2, 4 },
|
||||
"lua::loadScheduledScript"
|
||||
);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::loadScheduledScript");
|
||||
auto [time, forwardScript, backwardScript, universalScript] = ghoul::lua::values<
|
||||
std::string, std::string, std::optional<std::string>, std::optional<std::string>
|
||||
>(L);
|
||||
|
||||
scripting::ScriptScheduler::ScheduledScript script;
|
||||
|
||||
std::string time = ghoul::lua::value<std::string>(L, 1);
|
||||
script.time = Time::convertTime(time);
|
||||
std::string forwardScript = ghoul::lua::value<std::string>(L, 2);
|
||||
script.forwardScript = std::move(forwardScript);
|
||||
script.backwardScript = backwardScript.value_or(script.backwardScript);
|
||||
script.universalScript = universalScript.value_or(script.universalScript);
|
||||
|
||||
if (nArguments == 3) {
|
||||
std::string backwardScript = ghoul::lua::value<std::string>(L, 3);
|
||||
script.backwardScript = std::move(backwardScript);
|
||||
}
|
||||
else if (nArguments == 4) {
|
||||
std::string backwardScript = ghoul::lua::value<std::string>(L, 3);
|
||||
script.backwardScript = std::move(backwardScript);
|
||||
std::string universalScript = ghoul::lua::value<std::string>(L, 4);
|
||||
script.universalScript = std::move(universalScript);
|
||||
}
|
||||
std::vector<scripting::ScriptScheduler::ScheduledScript> scripts;
|
||||
scripts.push_back(std::move(script));
|
||||
global::scriptScheduler->loadScripts(scripts);
|
||||
|
||||
lua_settop(L, 0);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setModeApplicationTime(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::setModeApplicationTime");
|
||||
|
||||
global::scriptScheduler->setModeApplicationTime();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setModeRecordedTime(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::setModeRecordedTime");
|
||||
|
||||
global::scriptScheduler->setModeRecordedTime();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setModeSimulationTime(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::setModeSimulationTime");
|
||||
|
||||
global::scriptScheduler->setModeSimulationTime();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clear(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::clear");
|
||||
|
||||
global::scriptScheduler->clearSchedule();
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,9 +50,7 @@ bool lineSphereIntersection(glm::dvec3 p1, glm::dvec3 p2, glm::dvec3 center,
|
||||
// Intersection
|
||||
else {
|
||||
// Only care about the first intersection point if we have two
|
||||
const double t = static_cast<double>(
|
||||
(-b - std::sqrt(intersectionTest)) / (2.0 * a)
|
||||
);
|
||||
const double t = (-b - std::sqrt(intersectionTest)) / (2.0 * a);
|
||||
|
||||
// Check if utside of line segment between p1 and p2
|
||||
if (t <= 0 || t >= 1.0) {
|
||||
|
||||
@@ -406,21 +406,19 @@ bool HttpFileDownload::initDownload() {
|
||||
char buffer[255];
|
||||
LERROR(fmt::format(
|
||||
"Cannot open file '{}': {}",
|
||||
std::string(_destination),
|
||||
_destination,
|
||||
std::string(strerror_r(errno, buffer, sizeof(buffer)))
|
||||
));
|
||||
return false;
|
||||
#else
|
||||
LERROR(fmt::format(
|
||||
"Cannot open file '{}': {}",
|
||||
std::string(_destination),
|
||||
std::string(strerror(errno))
|
||||
"Cannot open file '{}': {}", _destination, std::string(strerror(errno))
|
||||
));
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
LERROR(fmt::format("Cannot open file {}", std::string(_destination)));
|
||||
LERROR(fmt::format("Cannot open file {}", _destination));
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ SpiceManager::KernelHandle SpiceManager::loadKernel(std::string filePath) {
|
||||
// kernels
|
||||
std::filesystem::path currentDirectory = std::filesystem::current_path();
|
||||
|
||||
std::filesystem::path p = std::filesystem::path(path).parent_path();
|
||||
std::filesystem::path p = path.parent_path();
|
||||
std::filesystem::current_path(p);
|
||||
|
||||
LINFO(fmt::format("Loading SPICE kernel {}", path));
|
||||
@@ -245,7 +245,7 @@ SpiceManager::KernelHandle SpiceManager::loadKernel(std::string filePath) {
|
||||
throwSpiceError("Kernel loading");
|
||||
}
|
||||
|
||||
std::filesystem::path fileExtension = std::filesystem::path(path).extension();
|
||||
std::filesystem::path fileExtension = path.extension();
|
||||
if (fileExtension == ".bc" || fileExtension == ".BC") {
|
||||
findCkCoverage(path.string()); // binary ck kernel
|
||||
}
|
||||
@@ -1362,14 +1362,14 @@ scripting::LuaLibrary SpiceManager::luaLibrary() {
|
||||
"getSpkCoverage",
|
||||
&luascriptfunctions::spkCoverage,
|
||||
{},
|
||||
"{string [, printValues]}",
|
||||
"string",
|
||||
"Returns a list of SPK coverage intervals for the target."
|
||||
},
|
||||
{
|
||||
"getCkCoverage",
|
||||
&luascriptfunctions::ckCoverage,
|
||||
{},
|
||||
"{string [, printValues]}",
|
||||
"string",
|
||||
"Returns a list of CK coverage intervals for the target."
|
||||
},
|
||||
{
|
||||
|
||||
+38
-159
@@ -38,20 +38,8 @@ namespace openspace::luascriptfunctions {
|
||||
|
||||
int loadKernel(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadKernel");
|
||||
std::string argument = ghoul::lua::value<std::string>(L);
|
||||
|
||||
bool isString = (lua_isstring(L, 1) == 1);
|
||||
if (!isString) {
|
||||
LERROR(fmt::format(
|
||||
"{}: Expected argument of type 'string'", ghoul::lua::errorLocation(L)
|
||||
));
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string argument = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
);
|
||||
if (!std::filesystem::is_regular_file(argument)) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
@@ -59,10 +47,7 @@ int loadKernel(lua_State* L) {
|
||||
);
|
||||
}
|
||||
unsigned int result = SpiceManager::ref().loadKernel(argument);
|
||||
|
||||
lua_pushnumber(L, result);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
|
||||
ghoul::lua::push(L, result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -72,37 +57,16 @@ int loadKernel(lua_State* L) {
|
||||
* automatically resolved.
|
||||
*/
|
||||
int unloadKernel(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadKernel");
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unloadKernel");
|
||||
std::variant<std::string, unsigned int> argument =
|
||||
ghoul::lua::value<std::variant<std::string, unsigned int>>(L);
|
||||
|
||||
bool isString = (lua_isstring(L, 1) == 1);
|
||||
bool isNumber = (lua_isnumber(L, 1) == 1);
|
||||
|
||||
if (!isString && !isNumber) {
|
||||
LERRORC(
|
||||
"loadKernel",
|
||||
fmt::format(
|
||||
"{}: Expected argument of type 'string' or 'number'",
|
||||
ghoul::lua::errorLocation(L)
|
||||
)
|
||||
);
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
if (std::holds_alternative<std::string>(argument)) {
|
||||
SpiceManager::ref().unloadKernel(std::get<std::string>(argument));
|
||||
}
|
||||
|
||||
if (isString) {
|
||||
std::string argument = ghoul::lua::value<std::string>(L, 1);
|
||||
SpiceManager::ref().unloadKernel(argument);
|
||||
else {
|
||||
SpiceManager::ref().unloadKernel(std::get<unsigned int>(argument));
|
||||
}
|
||||
|
||||
if (isNumber) {
|
||||
unsigned int argument = ghoul::lua::value<unsigned int>(L, 1);
|
||||
SpiceManager::ref().unloadKernel(argument);
|
||||
}
|
||||
|
||||
lua_settop(L, 0);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -111,13 +75,9 @@ int unloadKernel(lua_State* L) {
|
||||
* Returns the list of bodies loaded into the spicemanager
|
||||
*/
|
||||
int spiceBodies(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1,2 }, "lua::getSpiceBodies");
|
||||
bool isBool = (lua_isboolean(L, 1) == 1);
|
||||
const bool buildInBodies = isBool ? ghoul::lua::value<bool>(L, 1) : false;
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::spiceBodies");
|
||||
const bool buildInBodies = ghoul::lua::value<bool>(L);
|
||||
|
||||
isBool = (lua_isboolean(L, 2) == 1);
|
||||
bool printValues = isBool ? ghoul::lua::value<bool>(L, 2) : false;
|
||||
lua_settop(L, 0);
|
||||
std::vector<std::pair<int, std::string>> bodies = SpiceManager::ref().spiceBodies(
|
||||
buildInBodies
|
||||
);
|
||||
@@ -132,35 +92,20 @@ int spiceBodies(lua_State* L) {
|
||||
lua_rawset(L, -3);
|
||||
lua_rawseti(L, -2, number);
|
||||
++number;
|
||||
|
||||
if (printValues) {
|
||||
LINFO(fmt::format("Body id '{}' and name: {}", body.first, body.second));
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//internal function for getSpk and getCk coverages
|
||||
// internal function for getSpk and getCk coverages
|
||||
void buildLuaCoverageStack(lua_State* L,
|
||||
const std::vector<std::pair<double, double>>& coverage,
|
||||
bool printValues)
|
||||
const std::vector<std::pair<double, double>>& coverage)
|
||||
{
|
||||
lua_settop(L, 0);
|
||||
lua_newtable(L);
|
||||
int number = 1;
|
||||
for (const std::pair<double, double>& window : coverage) {
|
||||
std::string start = SpiceManager::ref().dateFromEphemerisTime(window.first);
|
||||
std::string end = SpiceManager::ref().dateFromEphemerisTime(window.second);
|
||||
|
||||
if (printValues) {
|
||||
LINFO(fmt::format(
|
||||
"Coverage start {} and end: {}",
|
||||
SpiceManager::ref().dateFromEphemerisTime(window.first),
|
||||
SpiceManager::ref().dateFromEphemerisTime(window.second)
|
||||
));
|
||||
}
|
||||
|
||||
lua_newtable(L);
|
||||
ghoul::lua::push(L, 1, start);
|
||||
lua_rawset(L, -3);
|
||||
@@ -172,97 +117,45 @@ void buildLuaCoverageStack(lua_State* L,
|
||||
}
|
||||
|
||||
/**
|
||||
* getSpkCoverage({string, bool(optional)}):
|
||||
* spkCoverage(string):
|
||||
* Returns the spk coverage for given body
|
||||
*/
|
||||
int spkCoverage(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::getSpkCoverage");
|
||||
const bool isString = (lua_isstring(L, 1) == 1);
|
||||
const bool isBool = (lua_isboolean(L, 2) == 1);
|
||||
|
||||
if (!isString) {
|
||||
LERRORC(
|
||||
"getSpkCoverage",
|
||||
fmt::format(
|
||||
"{}: Expected argument of type 'string'",
|
||||
ghoul::lua::errorLocation(L)
|
||||
)
|
||||
);
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string argument = ghoul::lua::value<std::string>(L, 1);
|
||||
|
||||
bool printValues = isBool ? ghoul::lua::value<bool>(L, 2) : false;
|
||||
buildLuaCoverageStack(L, SpiceManager::ref().spkCoverage(argument), printValues);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::spkCoverage");
|
||||
std::string argument = ghoul::lua::value<std::string>(L);
|
||||
|
||||
buildLuaCoverageStack(L, SpiceManager::ref().spkCoverage(argument));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* getCkCoverage({string, bool(optional)}):
|
||||
* ckCoverage(string):
|
||||
* Returns the spk coverage for given body
|
||||
*/
|
||||
int ckCoverage(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::getCkCoverage");
|
||||
|
||||
const bool isString = (lua_isstring(L, 1) == 1);
|
||||
const bool isBool = (lua_isboolean(L, 2) == 1);
|
||||
|
||||
if (!isString) {
|
||||
LERRORC(
|
||||
"getCkCoverage",
|
||||
fmt::format(
|
||||
"{}: Expected argument of type 'string'",
|
||||
ghoul::lua::errorLocation(L)
|
||||
)
|
||||
);
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string argument = ghoul::lua::value<std::string>(L, 1);
|
||||
bool printValues = isBool ? ghoul::lua::value<bool>(L, 2) : false;
|
||||
buildLuaCoverageStack(L, SpiceManager::ref().ckCoverage(argument), printValues);
|
||||
ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::ckCoverage");
|
||||
std::string argument = ghoul::lua::value<std::string>(L);
|
||||
|
||||
buildLuaCoverageStack(L, SpiceManager::ref().ckCoverage(argument));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* rotationMatrix({string, string, string}):
|
||||
* Returns the rotationMatrix for a given body in a frame of reference
|
||||
* at a specific time.
|
||||
* Returns the rotationMatrix for a given body in a frame of reference at a specific time
|
||||
*/
|
||||
int rotationMatrix(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::rotationMatrix");
|
||||
auto [body, frame, date] =
|
||||
ghoul::lua::values<std::string, std::string, std::string>(L);
|
||||
|
||||
const bool isString = (lua_isstring(L, 1) == 1) &&
|
||||
(lua_isstring(L, 2) == 1) && (lua_isstring(L, 3) == 1);
|
||||
|
||||
if (!isString) {
|
||||
LERRORC(
|
||||
"rotationMatrix",
|
||||
fmt::format(
|
||||
"{}: Expected argument of type 'string' for all three agruments",
|
||||
ghoul::lua::errorLocation(L)
|
||||
)
|
||||
);
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string body = ghoul::lua::value<std::string>(L, 1);
|
||||
std::string frame = ghoul::lua::value<std::string>(L, 2);
|
||||
std::string date = ghoul::lua::value<std::string>(L, 3);
|
||||
const double ephemerisTime = SpiceManager::ref().ephemerisTimeFromDate(date);
|
||||
glm::dmat3 rotationMatrix = SpiceManager::ref().frameTransformationMatrix
|
||||
(body, frame, ephemerisTime);
|
||||
glm::dmat3 rotationMatrix = SpiceManager::ref().frameTransformationMatrix(
|
||||
body,
|
||||
frame,
|
||||
ephemerisTime
|
||||
);
|
||||
ghoul::lua::push(L, 1, rotationMatrix);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -273,31 +166,17 @@ int rotationMatrix(lua_State* L) {
|
||||
*/
|
||||
int position(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::position");
|
||||
auto [target, observer, frame, date] =
|
||||
ghoul::lua::values<std::string, std::string, std::string, std::string>(L);
|
||||
|
||||
const bool isString = (lua_isstring(L, 1) == 1) &&
|
||||
(lua_isstring(L, 2) == 1) &&
|
||||
(lua_isstring(L, 3) == 1) &&
|
||||
(lua_isstring(L, 4) == 1);
|
||||
|
||||
if (!isString) {
|
||||
LERRORC(
|
||||
"position",
|
||||
fmt::format(
|
||||
"{}: Expected argument of type 'string' for all four agruments",
|
||||
ghoul::lua::errorLocation(L)
|
||||
)
|
||||
);
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string target = ghoul::lua::value<std::string>(L, 1);
|
||||
std::string observer = ghoul::lua::value<std::string>(L, 2);
|
||||
std::string frame = ghoul::lua::value<std::string>(L, 3);
|
||||
std::string date = ghoul::lua::value<std::string>(L, 4);
|
||||
const double ephemerisTime = SpiceManager::ref().ephemerisTimeFromDate(date);
|
||||
glm::dvec3 postion = SpiceManager::ref().targetPosition(target, observer, frame, {}, ephemerisTime);
|
||||
glm::dvec3 postion = SpiceManager::ref().targetPosition(
|
||||
target,
|
||||
observer,
|
||||
frame,
|
||||
{},
|
||||
ephemerisTime
|
||||
);
|
||||
ghoul::lua::push(L, 1, postion);
|
||||
|
||||
return 1;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user