Merge branch 'master' into thesis/2021/skybrowser

# Conflicts:
#	modules/webbrowser/CMakeLists.txt
This commit is contained in:
Ylva Selling
2022-04-04 16:14:50 -04:00
69 changed files with 3276 additions and 131 deletions

View File

@@ -42,6 +42,13 @@ set(HEADER_FILES
include/profile/timedialog.h
include/profile/profileedit.h
include/profile/propertiesdialog.h
include/sgctedit/displaywindowunion.h
include/sgctedit/filesupport.h
include/sgctedit/monitorbox.h
include/sgctedit/orientation.h
include/sgctedit/orientationdialog.h
include/sgctedit/sgctedit.h
include/sgctedit/windowcontrol.h
)
set(SOURCE_FILES
@@ -62,6 +69,13 @@ set(SOURCE_FILES
src/profile/timedialog.cpp
src/profile/profileedit.cpp
src/profile/propertiesdialog.cpp
src/sgctedit/sgctedit.cpp
src/sgctedit/displaywindowunion.cpp
src/sgctedit/filesupport.cpp
src/sgctedit/monitorbox.cpp
src/sgctedit/orientation.cpp
src/sgctedit/orientationdialog.cpp
src/sgctedit/windowcontrol.cpp
)
set(HEADER_SOURCE
@@ -79,6 +93,13 @@ set(HEADER_SOURCE
include/profile/timedialog.h
include/profile/profileedit.h
include/profile/propertiesdialog.h
include/sgctedit/displaywindowunion.h
include/sgctedit/filesupport.h
include/sgctedit/monitorbox.h
include/sgctedit/orientation.h
include/sgctedit/orientationdialog.h
include/sgctedit/sgctedit.h
include/sgctedit/windowcontrol.h
)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Widgets REQUIRED)
@@ -110,7 +131,13 @@ 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_include_directories(
openspace-ui-launcher
PUBLIC
include
${OPENSPACE_APPS_DIR}/OpenSpace/ext/sgct/include
${OPENSPACE_APPS_DIR}/OpenSpace/ext/sgct/sgct/ext/glm
)
target_link_libraries(
openspace-ui-launcher
PUBLIC

View File

@@ -27,7 +27,9 @@
#include <QMainWindow>
#include "sgctedit/sgctedit.h"
#include <openspace/scene/profile.h>
#include <QApplication>
#include <optional>
namespace openspace::configuration { struct Configuration; }
@@ -82,6 +84,7 @@ private:
void setBackgroundImage(const std::string& syncPath);
void openProfileEditor(const std::string& profile, bool isUserProfile);
void openWindowEditor();
void populateProfilesList(std::string preset);
void populateWindowConfigsList(std::string preset);

View File

@@ -0,0 +1,101 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___DISPLAYWINDOWUNION___H__
#define __OPENSPACE_UI_LAUNCHER___DISPLAYWINDOWUNION___H__
#include <QWidget>
#include "windowcontrol.h"
#include "monitorbox.h"
#include <QCheckBox>
#include <QComboBox>
#include <QIntValidator>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QPainter>
#include <QPainterPath>
#include <QPoint>
#include <QPushButton>
#include <QTextBrowser>
#include <QVector>
#include <vector>
class DisplayWindowUnion : public QWidget {
Q_OBJECT
public:
/**
* Constructor for DisplayWindowUnion class, which manages the overall control layout
* including monitorBox, multiple WindowControl columns, and additional controls
*
* \param monitorRenderBox pointer to the MonitorBox object
* \param monitorSizeList A vector containing QRect objects containing pixel dims
* of each monitor
* \param nMaxWindows The maximum number of windows allowed (depends on the number
* of monitors in the system)
* \param winColors An array of QColor objects for window colors. The indexing of
* this array matches the window indexing used elsewhere in the
* class. This allows for a unique color for each window.
*/
DisplayWindowUnion(std::shared_ptr<MonitorBox> monitorRenderBox,
std::vector<QRect>& monitorSizeList, unsigned int nMaxWindows,
const std::array<QColor, 4>& winColors);
/**
* Returns a vector of pointers to all WindowControl objects for all windows
*
* \return vector of pointers of WindowControl objects
*/
std::vector<std::shared_ptr<WindowControl>> windowControls() const;
/**
* Returns the current number of windows
*
* \return the currently-selected number of windows in unsigned int
*/
unsigned int nWindows() const;
private slots:
void addWindow();
void removeWindow();
private:
void initializeWindowControl();
void initializeLayout();
void showWindows();
std::shared_ptr<MonitorBox> _monBox;
std::vector<QRect>& _monitorResolutions;
unsigned int _nWindowsAllocated = 0;
unsigned int _nWindowsDisplayed = 0;
unsigned int _nMaxWindows = 3;
const std::array<QColor, 4>& _winColors;
std::vector<std::shared_ptr<WindowControl>> _windowControl;
QPushButton* _addWindowButton = nullptr;
QPushButton* _removeWindowButton = nullptr;
unsigned int _monitorIdx = 0;
std::vector<QVBoxLayout*> _winCtrlLayouts;
std::vector<QWidget*> _layoutWindowWrappers;
std::vector<QFrame*> _frameBorderLines;
QFrame* _borderFrame = nullptr;
};
#endif // __OPENSPACE_UI_LAUNCHER___DISPLAYWINDOWUNION___H__

View File

@@ -0,0 +1,119 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___FILESUPPORT___H__
#define __OPENSPACE_UI_LAUNCHER___FILESUPPORT___H__
#include <QWidget>
#include <ghoul/filesystem/filesystem.h>
#include <sgctedit/displaywindowunion.h>
#include <sgctedit/orientation.h>
#include <sgct/config.h>
#include <QFileDialog>
#include <QFrame>
#include <QLabel>
#include <QLayout>
#include <QPushButton>
#include <QVector>
#include <filesystem>
#include <memory>
#include <vector>
using ProjectionOptions = std::variant<
sgct::config::NoProjection,
sgct::config::CylindricalProjection,
sgct::config::EquirectangularProjection,
sgct::config::FisheyeProjection,
sgct::config::PlanarProjection,
sgct::config::ProjectionPlane,
sgct::config::SphericalMirrorProjection,
sgct::config::SpoutOutputProjection,
sgct::config::SpoutFlatProjection
>;
struct SgctConfigElements {
std::vector<sgct::config::Window>& windowList;
sgct::config::Cluster& cluster;
};
struct UserConfigurationElements {
std::vector<QRect>& monitorList;
std::shared_ptr<DisplayWindowUnion> display;
Orientation* orientation;
const std::string configSavePath;
};
class FileSupport : public QWidget {
Q_OBJECT
public:
/**
* Constructor for FileSupport class, which saves the window configuration settings
* into the SGCT json structure according to the sgct code
*
* \param parentLayout Qt vertical (QVBoxLayout) layout where controls are added
* \param cfgElements struct of elements needed to read user settings from GUI
* \param sgctElements struct of the window and cluster objects needed for saving
* \param finishedCallback function to be called when user has selected to either
* save changes to file, apply and run without saving, or cancel
*/
FileSupport(QVBoxLayout* parentLayout, UserConfigurationElements& cfgElements,
SgctConfigElements& sgctElements, std::function<void(bool)> finishedCallback);
std::string saveFilename();
private slots:
void cancel();
void save();
void apply();
private:
bool isWindowFullscreen(unsigned int monitorIdx, sgct::ivec2 wDims);
std::optional<unsigned int> findGuiWindow();
void saveConfigToSgctFormat();
void saveCluster();
void saveWindows();
void saveUser();
ProjectionOptions saveProjectionInformation(
std::shared_ptr<WindowControl> winControl);
ProjectionOptions saveProjectionSpout(std::shared_ptr<WindowControl> winControl);
ProjectionOptions saveProjectionNoSpout(std::shared_ptr<WindowControl> winControl);
sgct::config::Viewport generateViewport();
sgct::config::Window saveWindowsDimensions(std::shared_ptr<WindowControl> wCtrl);
void saveWindowsWebGui(unsigned int wIdx, sgct::config::Window& win);
QHBoxLayout* _layoutButtonBox = nullptr;
QPushButton* _saveButton = nullptr;
QPushButton* _cancelButton = nullptr;
QPushButton* _applyButton = nullptr;
std::shared_ptr<DisplayWindowUnion> _displayWidget;
Orientation* _orientationWidget;
std::vector<QRect>& _monitors;
sgct::config::Cluster& _cluster;
std::vector<sgct::config::Window>& _windowList;
std::function<void(bool)> _finishedCallback;
const std::string _userConfigPath;
std::string _saveTarget;
};
#endif // __OPENSPACE_UI_LAUNCHER___FILESUPPORT___H__

View File

@@ -0,0 +1,126 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___MONITORBOX___H__
#define __OPENSPACE_UI_LAUNCHER___MONITORBOX___H__
#include <QWidget>
#include "windowcontrol.h"
#include <QColor>
#include <QIntValidator>
#include <QLineEdit>
#include <QPainter>
#include <QPainterPath>
#include <QPoint>
#include <QVector>
#include <algorithm>
#include <array>
#include <vector>
#include <iostream>
class MonitorBox : public QWidget {
Q_OBJECT
public:
/**
* Constructor for MonitorBox class, which displays the system's monitor(s),
* their relative position and size, and window(s) that they contain
*
* \param widgetDims The size of the display widget in pixels, stored in QRect
* \param monitorResolution A vector containing the monitor's maximum display
* size in pixels in a QRect object
* \param nWindows The current number of windows that has been selected by the user
* \param winColors An array of QColor objects for window colors. The indexing of
* this array matches the window indexing used elsewhere in the
* class. This allows for a unique color for each window.
*/
MonitorBox(QRect widgetDims, std::vector<QRect> monitorResolution,
unsigned int nWindows, const std::array<QColor, 4>& winColors);
/**
* Maps window resolution into the scaled resolution of the display widget
*
* \param mIdx The zero-based monitor index (primary monitor is 0)
* \param wIdx The zero-based window index
* \param winDimensions Dimensions (pixels) of window to be mapped in QRect
*/
void mapWindowResolutionToWidgetCoordinates(unsigned int mIdx, unsigned int wIdx,
const QRectF& winDimensions);
/**
* Sets the number of windows to be displayed
*
* \param nWindows Number of windows to be displayed
*/
void setNumWindowsDisplayed(unsigned int nWindows);
/**
* Called when window dimensions or monitor location have changed, requiring redraw
*
* \param mIdx The zero-based monitor index (primary monitor is 0)
* \param wIdx The zero-based window index
* \param newDimensions Dimensions (pixels) of window to be mapped in QRect
*/
void windowDimensionsChanged(unsigned int mIdx, unsigned int wIdx,
const QRectF& newDimensions);
protected:
void paintEvent(QPaintEvent* event) override;
private:
void determineMonitorArrangement();
void mapMonitorResolutionToWidgetCoordinates();
void paintWidgetBorder(QPainter& painter, int width, int height);
void paintMonitorBackgrounds(QPainter& painter);
void paintWindow(QPainter& painter, size_t winIdx);
void paintWindowBeyondBounds(QPainter& painter, unsigned int winIdx);
void paintWindowNumber(QPainter& painter, unsigned int winIdx);
void setPenSpecificToWindow(QPainter& painter, unsigned int windowIdx,
bool visibleBorder);
void computeScaledResolutionLandscape(float aspectRatio, float maxWidth);
void computeScaledResolutionPortrait(float aspectRatio, float maxHeight);
unsigned int _maxNumMonitors = 2;
QRectF _monitorWidgetSize;
QRectF _monitorBoundaryRect;
unsigned int _nMonitors = 1;
float _monitorArrangementAspectRatio = 1.f;
QSizeF _monitorArrangementDimensions = { 0.0, 0.0 };
std::vector<QRect> _monitorResolution;
std::vector<QRectF> _monitorDimensionsScaled;
QRectF _negativeCorrectionOffsets = {0.f, 0.f, 0.f, 0.f};
std::vector<QRectF> _windowResolutions;
std::vector<QRectF> _windowRendering = {
{0.f, 0.f, 0.f, 0.f},
{0.f, 0.f, 0.f, 0.f},
{0.f, 0.f, 0.f, 0.f},
{0.f, 0.f, 0.f, 0.f}
};
unsigned int _nWindows = 1;
const std::array<QColor, 4> _colorsForWindows;
int _alphaWindowOpacity = 170;
float _monitorScaleFactor = 1.0;
bool _showLabel = false;
float _marginWidget = 5.0;
std::vector<QSizeF> _monitorOffsets;
};
#endif // __OPENSPACE_UI_LAUNCHER___MONITORBOX___H__

View File

@@ -0,0 +1,83 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___ORIENTATION___H__
#define __OPENSPACE_UI_LAUNCHER___ORIENTATION___H__
#include <QWidget>
#include <sgctedit/orientationdialog.h>
#include <sgct/config.h>
#include <sgct/math.h>
#include <QCheckBox>
#include <QLayout>
#include <QPushButton>
class Orientation : public QWidget {
Q_OBJECT
public:
/**
* Constructor for Orientation class, which manages the overall control layout
* including monitorBox, multiple WindowControl columns, and additional controls
*
* \param monitorRenderBox pointer to the MonitorBox object
* \param monitorSizeList A vector containing QRect objects containing pixel dims
* of each monitor
* \param nMaxWindows The maximum number of windows allowed (depends on the number
* of monitors in the system)
* \param winColors An array of QColor objects for window colors. The indexing of
* this array matches the window indexing used elsewhere in the
* class. This allows for a unique color for each window.
*/
Orientation();
/**
* Add Orientation controls to the parent layout
*
* \param parentLayout the layout to which the Orientation's controls will be added
*/
void addControlsToParentLayout(QVBoxLayout* parentLayout);
/**
* Gets the user-provided x,y,z orientation values (degrees)
*
* \return the orientation angles provided in sgct::quat object
*/
sgct::quat orientationValue() const;
/**
* Gets the value for if VSync is enabled
*
* \return true if the VSync option is checked/enabled
*/
bool vsyncValue() const;
private slots:
void orientationDialog();
private:
sgct::quat _orientationValue = {0.f, 0.f, 0.f, 0.f};
OrientationDialog _orientationDialog;
QHBoxLayout* _layoutOrientationFull = nullptr;
QCheckBox* _checkBoxVsync = nullptr;
};
#endif // __OPENSPACE_UI_LAUNCHER___ORIENTATION___H__

View File

@@ -0,0 +1,59 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___ORIENTATIONDIALOG___H__
#define __OPENSPACE_UI_LAUNCHER___ORIENTATIONDIALOG___H__
#include <QDialog>
#include <sgct/config.h>
#include <QLineEdit>
#include <glm/gtc/constants.hpp>
class QWidget;
class OrientationDialog : public QDialog {
Q_OBJECT
public:
/**
* Constructor for OrientationDialog object which contains the input text boxes for
* orientation x,y,z values
*
* \param orientation x,y,z angles in degrees contained in sgct::quat object
* \param parent pointer to Qt QWidget parent object
*/
OrientationDialog(sgct::quat& orientation, QWidget* parent);
private slots:
void cancel();
void ok();
private:
QLineEdit* _linePitch = nullptr;
QLineEdit* _lineRoll = nullptr;
QLineEdit* _lineYaw = nullptr;
sgct::quat& _orientationValue;
};
#endif // __OPENSPACE_UI_LAUNCHER___ORIENTATIONDIALOG___H__

View File

@@ -0,0 +1,105 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___SGCTEDIT___H__
#define __OPENSPACE_UI_LAUNCHER___SGCTEDIT___H__
#include <QDialog>
#include <sgctedit/displaywindowunion.h>
#include <sgctedit/filesupport.h>
#include <sgctedit/monitorbox.h>
#include <sgctedit/orientation.h>
#include <QApplication>
#include <QColor>
#include <QLayout>
#include <QScreen>
#include <memory>
#include <string>
#include <vector>
class QWidget;
class SgctEdit final : public QDialog {
Q_OBJECT
public:
/**
* Constructor for SgctEdit class, the underlying class for the full window
* configuration editor
*
* \param parent The Qt QWidget parent object
* \param windowList vector of sgct::config::Window objects which will be modified
* by the user settings, and then used for writing to file in
* the launcher code
* \param cluster reference to sgct::config::Cluster object that contains sgct
* objects that will be modified by the window configuration settings
* \param screenList A QList containing a QScreen object for each monitor in the
* system
* \param userConfigPath A string containing the file path of the user config
* directory where all window configs are stored
*/
SgctEdit(QWidget* parent, std::vector<sgct::config::Window>& windowList,
sgct::config::Cluster& cluster, const QList<QScreen*>& screenList,
const std::string userConfigPath);
~SgctEdit();
/**
* Used to determine if the window configuration was saved to file, or canceled
*
* \return true if configuration was saved to file
*/
bool wasSaved() const;
/**
* Returns the saved filename
*
* \return saved filename in std::string
*/
std::string saveFilename();
private:
void addDisplayLayout(QHBoxLayout* layout);
void createWidgets();
void systemMonitorConfiguration(const QList<QScreen*>& screenList);
std::shared_ptr<MonitorBox> _monBox = nullptr;
std::vector<QRect> _monitorSizeList;
QVBoxLayout* _displayLayout = nullptr;
QFrame* _displayFrame = nullptr;
std::shared_ptr<DisplayWindowUnion> _displayWidget = nullptr;
QRect _monitorWidgetSize = {0, 0, 500, 500};
FileSupport* _fileSupportWidget = nullptr;
Orientation* _orientationWidget = nullptr;
sgct::config::Cluster& _cluster;
std::vector<sgct::config::Window>& _windowList;
const std::string _userConfigPath;
bool _saveSelected = false;
unsigned int _nMaxWindows = 3;
const std::array<QColor, 4> _colorsForWindows = {
QColor(0x2B, 0x9E, 0xC3),
QColor(0xFC, 0xAB, 0x10),
QColor(0x44, 0xAF, 0x69),
QColor(0xF8, 0x33, 0x3C)
};
};
#endif // __OPENSPACE_UI_LAUNCHER___SGCTEDIT___H__

View File

@@ -0,0 +1,251 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___WINDOWCONTROL___H__
#define __OPENSPACE_UI_LAUNCHER___WINDOWCONTROL___H__
#include <QWidget>
#include <sgct/config.h>
#include <QCheckBox>
#include <QComboBox>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QPushButton>
#include <vector>
class WindowControl : public QWidget {
Q_OBJECT
public:
/**
* Constructor for WindowControl class, which contains settings and configuration
* for individual windows
*
* \param monitorIndex The zero-based index for monitor number that this window
* resides in
* \param windowIndex The zero-based window index
* \param monitorDims Vector of monitor dimensions in QRect form
* \param winColor A QColor object for this window's unique color
*/
WindowControl(unsigned int monitorIndex, unsigned int windowIndex,
std::vector<QRect>& monitorDims, const QColor& winColor,
QWidget *parent);
~WindowControl();
/**
* Sets callback function to be invoked when a window's setting changes
*
* \param cb Callback function that accepts the listed arg types, in order of
* monitorIndex, windowIndex, and windowDims (that were just changed)
*/
void setWindowChangeCallback(std::function<void(int, int, const QRectF&)> cb);
/**
* Sets callback function to be invoked when a window gets its GUI checkbox selected
*
* \param cb Callback function that accepts the index of the window that has its
* WebGUI option selected
*/
void setWebGuiChangeCallback(std::function<void(unsigned int)> cb);
/**
* Makes the window label at top of a window control column visible
*
* \param bool Shows the window label if true
*/
void showWindowLabel(bool show);
/**
* Initializes the layout of a window controls column, returning the Qt layout object
*
* \return the QVBoxLayout object that contains the entire windows control column
*/
QVBoxLayout* initializeLayout();
/**
* Returns the dimensions of the window
*
* \return the QRectF object that contains the windows dimensions
*/
QRectF& dimensions();
/**
* Returns the title name of the window
*
* \return the std::string of the window name
*/
std::string windowName() const;
/**
* Returns the user-entered window size width, height from the text line objects
*
* \return the user-entered window size in sgct::ivec2 object
*/
sgct::ivec2 windowSize() const;
/**
* Returns the user-entered window position in x,y pixles from the text line objects
*
* \return the user-entered window position in sgct::ivec2 object
*/
sgct::ivec2 windowPos() const;
/**
* Returns bool for if the window control checkbox is set to be decorated
*
* \return bool for if window decoration is enabled
*/
bool isDecorated() const;
/**
* Returns bool for if the window control checkbox spout selection is enabled
*
* \return bool for if window has spout enabled
*/
bool isSpoutSelected() const;
/**
* Returns bool for if the window control checkbox for WebGUI is enabled
*
* \return bool for if window has WebGUI enabled
*/
bool isGuiWindow() const;
/**
* Function called in order to disable/uncheck the WebGUI checkbox option
*/
void uncheckWebGuiOption();
/**
* Returns index number of the selected window quality value. This is an index into
* the QualityValues array
*
* \return index int into the QualityValues array
*/
int qualitySelectedValue() const;
/**
* Returns index number of the monitor that this window is assigned to
*
* \return int index of monitor
*/
unsigned int monitorNum() const;
/**
* Returns the user-entered horizontal field-of-view (planar projection only)
*
* \return float value of horizontal FOV
*/
float fovH() const;
/**
* Returns the user-entered vertical field-of-view (planar projection only)
*
* \return float value of vertical FOV
*/
float fovV() const;
/**
* Returns the user-entered height offset (cylindrical projection only)
*
* \return float value of height offset
*/
float heightOffset() const;
enum class ProjectionIndeces {
Planar = 0,
Fisheye,
SphericalMirror,
Cylindrical,
Equirectangular
};
/**
* Returns the user-selected window projection type
*
* \return ProjectionIndeces enum of the projection type
*/
ProjectionIndeces projectionSelectedIndex() const;
/**
* Resets all controls for this window to default settings
*/
void resetToDefaults();
private slots:
void onSizeXChanged(const QString& newText);
void onSizeYChanged(const QString& newText);
void onOffsetXChanged(const QString& newText);
void onOffsetYChanged(const QString& newText);
void onMonitorChanged(int newSelection);
void onProjectionChanged(int newSelection);
void onFullscreenClicked();
void onSpoutSelection(int selectionState);
void onWebGuiSelection(int selectionState);
void onAspectRatioLockClicked();
void onFovLockClicked();
private:
void createWidgets(QWidget* parent);
void determineIdealWindowSize();
QString resolutionLabelText(QRect resolution);
void updatePlanarLockedFov();
void updateScaledWindowDimensions();
std::function<void(int, int, const QRectF&)> _windowChangeCallback;
std::function<void(unsigned int)> _windowGuiCheckCallback;
QRectF defaultWindowSizes[4] = {
{50.f, 50.f, 1280.f, 720.f},
{150.f, 150.f, 1280.f, 720.f},
{50.f, 50.f, 1280.f, 720.f},
{150.f, 150.f, 1280.f, 720.f}
};
QList<QString> _monitorNames = { "Primary", "Secondary" };
int QualityValues[10] = { 256, 512, 1024, 1536, 2048, 4096, 8192, 16384,
32768, 65536 };
int _lineEditWidthFixedWinSize = 50;
int _lineEditWidthFixedFov = 80;
const float _idealAspectRatio = 16.f / 9.f;
float _aspectRatioSize = _idealAspectRatio;
float _marginFractionOfWidgetSize = 0.025f;
float _defaultFovH = 80.f;
float _defaultFovV = 50.534f;
float _defaultHeightOffset = 0.f;
unsigned int _nMonitors = 1;
unsigned int _monIndex = 0;
unsigned int _monIndexDefault = 0;
unsigned int _index = 0;
bool _aspectRatioLocked = false;
bool _FovLocked = true;
std::vector<QRect>& _monitorResolutions;
int _maxWindowSizePixels = 10000;
const QColor& _colorForWindow;
QVBoxLayout* _layoutFullWindow = nullptr;
QLabel* _labelWinNum = nullptr;
QLineEdit* _sizeX = nullptr;
QLineEdit* _sizeY = nullptr;
QLineEdit* _offsetX = nullptr;
QLineEdit* _offsetY = nullptr;
QPushButton* _buttonLockAspectRatio = nullptr;
QPushButton* _buttonLockFov = nullptr;
QRectF _windowDims;
QPushButton* _fullscreenButton = nullptr;
QCheckBox* _checkBoxWindowDecor = nullptr;
QCheckBox* _checkBoxWebGui = nullptr;
QCheckBox* _checkBoxSpoutOutput = nullptr;
QComboBox* _comboMonitorSelect = nullptr;
QComboBox* _comboProjection = nullptr;
QComboBox* _comboQuality = nullptr;
QLabel* _labelQuality = nullptr;
QLabel* _labelFovH = nullptr;
QLineEdit* _lineFovH = nullptr;
QLabel* _labelFovV = nullptr;
QLineEdit* _lineFovV = nullptr;
QLabel* _labelHeightOffset = nullptr;
QLineEdit* _lineHeightOffset = nullptr;
QLineEdit* _windowName = nullptr;
QIcon _lockIcon;
QIcon _unlockIcon;
};
#endif // __OPENSPACE_UI_LAUNCHER___WINDOWCONTROL___H__

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -3,5 +3,7 @@
<file>qss/launcher.qss</file>
<file>images/openspace-horiz-logo-small.png</file>
<file>images/launcher-background.png</file>
<file>images/outline_locked.png</file>
<file>images/outline_unlocked.png</file>
</qresource>
</RCC>

View File

@@ -40,6 +40,7 @@
#include <fstream>
#include <iostream>
#include <random>
#include <sgct/readconfig.h>
using namespace openspace;
@@ -61,18 +62,24 @@ namespace {
constexpr const QRect ProfileBox(
LeftRuler, TopRuler + 110, ItemWidth, ItemHeight
);
constexpr const QRect OptionsLabel(LeftRuler, TopRuler + 180, 151, 24);
constexpr const QRect NewProfileButton(
LeftRuler + 140, TopRuler + 180, SmallItemWidth, SmallItemHeight
);
constexpr const QRect EditProfileButton(
LeftRuler, TopRuler + 180, SmallItemWidth, SmallItemHeight
);
constexpr const QRect OptionsLabel(LeftRuler, TopRuler + 230, 151, 24);
constexpr const QRect WindowConfigBox(
LeftRuler, TopRuler + 210, ItemWidth, ItemHeight
LeftRuler, TopRuler + 260, ItemWidth, ItemHeight
);
constexpr const QRect NewWindowButton(
LeftRuler + 140, TopRuler + 330, SmallItemWidth, SmallItemHeight
);
constexpr const QRect EditWindowButton(
LeftRuler, TopRuler + 330, SmallItemWidth, SmallItemHeight
);
constexpr const QRect StartButton(
LeftRuler, TopRuler + 290, ItemWidth, ItemHeight
);
constexpr const QRect NewButton(
LeftRuler + 140, TopRuler + 380, SmallItemWidth, SmallItemHeight
);
constexpr const QRect EditButton(
LeftRuler, TopRuler + 380, SmallItemWidth, SmallItemHeight
LeftRuler, TopRuler + 400, ItemWidth, ItemHeight
);
} // geometry
@@ -134,6 +141,25 @@ namespace {
);
}
}
void saveWindowConfig(QWidget* parent, const std::string& path,
sgct::config::Cluster& cluster)
{
std::ofstream outFile;
try {
outFile.open(path, std::ofstream::out);
outFile << sgct::serializeConfig(cluster);
}
catch (const std::ofstream::failure& e) {
QMessageBox::critical(
parent,
"Exception",
QString::fromStdString(fmt::format(
"Error writing data to file: {} ({})", path, e.what()
))
);
}
}
} // namespace
using namespace openspace;
@@ -248,20 +274,20 @@ QWidget* LauncherWindow::createCentralWidget() {
startButton->setGeometry(geometry::StartButton);
startButton->setCursor(Qt::PointingHandCursor);
QPushButton* newButton = new QPushButton("New", centralWidget);
QPushButton* newProfileButton = new QPushButton("New", centralWidget);
connect(
newButton, &QPushButton::released,
newProfileButton, &QPushButton::released,
[this]() {
openProfileEditor("", true);
}
);
newButton->setObjectName("small");
newButton->setGeometry(geometry::NewButton);
newButton->setCursor(Qt::PointingHandCursor);
newProfileButton->setObjectName("small");
newProfileButton->setGeometry(geometry::NewProfileButton);
newProfileButton->setCursor(Qt::PointingHandCursor);
QPushButton* editButton = new QPushButton("Edit", centralWidget);
QPushButton* editProfileButton = new QPushButton("Edit", centralWidget);
connect(
editButton, &QPushButton::released,
editProfileButton, &QPushButton::released,
[this]() {
const std::string selection = _profileBox->currentText().toStdString();
int selectedIndex = _profileBox->currentIndex();
@@ -269,9 +295,20 @@ QWidget* LauncherWindow::createCentralWidget() {
openProfileEditor(selection, isUserProfile);
}
);
editButton->setObjectName("small");
editButton->setGeometry(geometry::EditButton);
editButton->setCursor(Qt::PointingHandCursor);
editProfileButton->setObjectName("small");
editProfileButton->setGeometry(geometry::EditProfileButton);
editProfileButton->setCursor(Qt::PointingHandCursor);
QPushButton* newWindowButton = new QPushButton("New", centralWidget);
connect(
newWindowButton, &QPushButton::released,
[this]() {
openWindowEditor();
}
);
newWindowButton->setObjectName("small");
newWindowButton->setGeometry(geometry::NewWindowButton);
newWindowButton->setCursor(Qt::PointingHandCursor);
return centralWidget;
}
@@ -354,13 +391,18 @@ void LauncherWindow::populateProfilesList(std::string preset) {
++_userAssetCount;
// Add all the files with the .profile extension to the dropdown
std::vector<fs::directory_entry> profiles;
for (const fs::directory_entry& p : fs::directory_iterator(_userProfilePath)) {
if (p.path().extension() != ".profile") {
continue;
}
_profileBox->addItem(QString::fromStdString(p.path().stem().string()));
profiles.push_back(p);
++_userAssetCount;
}
std::sort(profiles.begin(), profiles.end());
for (const fs::directory_entry& p : profiles) {
_profileBox->addItem(QString::fromStdString(p.path().stem().string()));
}
_profileBox->addItem(QString::fromStdString("--- OpenSpace Profiles ---"));
model = qobject_cast<const QStandardItemModel*>(_profileBox->model());
@@ -368,11 +410,17 @@ void LauncherWindow::populateProfilesList(std::string preset) {
++_userAssetCount;
// Add all the files with the .profile extension to the dropdown
for (const fs::directory_entry& p : fs::directory_iterator(_profilePath)) {
if (p.path().extension() != ".profile") {
profiles.clear();
for (const fs::directory_entry& path : fs::directory_iterator(_profilePath)) {
if (path.path().extension() != ".profile") {
continue;
}
_profileBox->addItem(QString::fromStdString(p.path().stem().string()));
profiles.push_back(path);
}
std::sort(profiles.begin(), profiles.end());
//add sorted items to list
for (const fs::directory_entry& profile : profiles) {
_profileBox->addItem(QString::fromStdString(profile.path().stem().string()));
}
// Try to find the requested profile and set it as the current one
@@ -414,8 +462,15 @@ void LauncherWindow::populateWindowConfigsList(std::string preset) {
bool hasXmlConfig = false;
// Add all the files with the .xml or .json extension to the dropdown
//sort files
std::vector<fs::directory_entry> files;
for (const fs::directory_entry& p : fs::directory_iterator(_userConfigPath)) {
files.push_back(p);
}
std::sort(files.begin(), files.end());
// Add all the files with the .xml or .json extension to the dropdown
for (const fs::directory_entry& p : files) {
bool isConfigFile = handleConfigurationFile(*_windowConfigBox, p);
if (isConfigFile) {
++_userConfigCount;
@@ -428,8 +483,14 @@ void LauncherWindow::populateWindowConfigsList(std::string preset) {
model->item(_userConfigCount)->setEnabled(false);
if (std::filesystem::exists(_configPath)) {
// Add all the files with the .xml or .json extension to the dropdown
//sort files
files.clear();
for (const fs::directory_entry& p : fs::directory_iterator(_configPath)) {
files.push_back(p);
}
std::sort(files.begin(), files.end());
// Add all the files with the .xml or .json extension to the dropdown
for (const fs::directory_entry& p : files) {
handleConfigurationFile(*_windowConfigBox, p);
hasXmlConfig |= p.path().extension() == ".xml";
}
@@ -452,6 +513,8 @@ void LauncherWindow::populateWindowConfigsList(std::string preset) {
);
}
//Always add the .cfg sgct default as first item
_windowConfigBox->insertItem(0, QString::fromStdString(_sgctConfigName));
// Try to find the requested configuration file and set it as the current one. As we
// have support for function-generated configuration files that will not be in the
// list we need to add a preset that doesn't exist a file for
@@ -461,8 +524,11 @@ void LauncherWindow::populateWindowConfigsList(std::string preset) {
}
else {
// Add the requested preset at the top
_windowConfigBox->insertItem(0, QString::fromStdString(preset));
_windowConfigBox->setCurrentIndex(0);
_windowConfigBox->insertItem(1, QString::fromStdString(preset));
//Increment the user config count because there is an additional option added
//before the user config options
_userConfigCount++;
_windowConfigBox->setCurrentIndex(1);
}
}
@@ -500,6 +566,44 @@ void LauncherWindow::openProfileEditor(const std::string& profile, bool isUserPr
}
}
void LauncherWindow::openWindowEditor() {
QList<QScreen*> screenList = qApp->screens();
if (screenList.length() == 0) {
LERRORC(
"LauncherWindow",
"Error: Qt reports no screens/monitors available"
);
return;
}
sgct::config::Cluster cluster;
std::vector<sgct::config::Window> windowList;
SgctEdit editor(this, windowList, cluster, screenList, _userConfigPath);
editor.exec();
if (editor.wasSaved()) {
std::string ext = ".json";
std::string savePath = editor.saveFilename();
if (savePath.size() >= ext.size()
&& !(savePath.substr(savePath.size() - ext.size()).compare(ext) == 0))
{
savePath += ext;
}
if (cluster.nodes.size() == 0) {
cluster.nodes.push_back(sgct::config::Node());
}
for (auto w : windowList) {
cluster.nodes[0].windows.push_back(w);
}
saveWindowConfig(this, savePath, cluster);
//Truncate path to convert this back to path relative to _userConfigPath
savePath = savePath.substr(_userConfigPath.size());
populateWindowConfigsList(savePath);
}
else {
const std::string current = _windowConfigBox->currentText().toStdString();
populateWindowConfigsList(current);
}
}
bool LauncherWindow::wasLaunchSelected() const {
return _shouldLaunch;
}

View File

@@ -0,0 +1,179 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/displaywindowunion.h"
#include <ghoul/fmt.h>
#include "sgctedit/monitorbox.h"
#include "sgctedit/windowcontrol.h"
#include <QApplication>
#include <QMainWindow>
#include <QScreen>
#include <string>
DisplayWindowUnion::DisplayWindowUnion(std::shared_ptr<MonitorBox> monitorRenderBox,
std::vector<QRect>& monitorSizeList, unsigned int nMaxWindows,
const std::array<QColor, 4>& winColors)
: _monBox(monitorRenderBox)
, _monitorResolutions(monitorSizeList)
, _nMaxWindows(nMaxWindows)
, _winColors(winColors)
{
_addWindowButton = new QPushButton("Add Window");
_removeWindowButton = new QPushButton("Remove Window");
//Add all window controls (some will be hidden from GUI initially)
for (unsigned int i = 0; i < _nMaxWindows; ++i) {
initializeWindowControl();
}
connect(
_addWindowButton,
&QPushButton::clicked,
this,
&DisplayWindowUnion::addWindow
);
connect(
_removeWindowButton,
&QPushButton::clicked,
this,
&DisplayWindowUnion::removeWindow
);
initializeLayout();
}
void DisplayWindowUnion::initializeLayout() {
QVBoxLayout* layout = new QVBoxLayout(this);
{
QHBoxLayout* layoutMonButton = new QHBoxLayout;
_removeWindowButton->setToolTip(
"Remove window from the configuration (at least one window is required)"
);
std::string addTip = fmt::format(
"Add a window to the configuration (up to {} windows allowed)", _nMaxWindows
);
_addWindowButton->setToolTip(QString::fromStdString(addTip));
_addWindowButton->setFocusPolicy(Qt::NoFocus);
_removeWindowButton->setFocusPolicy(Qt::NoFocus);
layoutMonButton->addWidget(_removeWindowButton);
layoutMonButton->addStretch(1);
layoutMonButton->addWidget(_addWindowButton);
layout->addLayout(layoutMonButton);
}
QHBoxLayout* layoutWindows = new QHBoxLayout;
layout->addStretch();
for (unsigned int i = 0; i < _nMaxWindows; ++i) {
QVBoxLayout* layoutForNextWindow = _windowControl[i]->initializeLayout();
_winCtrlLayouts.push_back(layoutForNextWindow);
QWidget* layoutWrapper = new QWidget();
layoutWrapper->setLayout(layoutForNextWindow);
_layoutWindowWrappers.push_back(layoutWrapper);
layoutWindows->addWidget(layoutWrapper);
if (i < (_nMaxWindows - 1)) {
QFrame* frameForNextWindow = new QFrame();
frameForNextWindow->setFrameShape(QFrame::VLine);
_frameBorderLines.push_back(frameForNextWindow);
layoutWindows->addWidget(frameForNextWindow);
}
}
_nWindowsDisplayed = 1;
showWindows();
layout->addLayout(layoutWindows);
}
std::vector<std::shared_ptr<WindowControl>> DisplayWindowUnion::windowControls() const {
return _windowControl;
}
unsigned int DisplayWindowUnion::nWindows() const {
return _nWindowsDisplayed;
}
void DisplayWindowUnion::addWindow() {
if (_nWindowsDisplayed < _nMaxWindows) {
_windowControl[_nWindowsDisplayed]->resetToDefaults();
_nWindowsDisplayed++;
showWindows();
}
}
void DisplayWindowUnion::removeWindow() {
if (_nWindowsDisplayed > 1) {
_nWindowsDisplayed--;
showWindows();
}
}
void DisplayWindowUnion::showWindows() {
for (size_t i = 0; i < _layoutWindowWrappers.size(); ++i) {
_layoutWindowWrappers[i]->setVisible(i < _nWindowsDisplayed);
}
for (size_t i = 0; i < _frameBorderLines.size(); ++i) {
_frameBorderLines[i]->setVisible(i < (_nWindowsDisplayed - 1));
}
_removeWindowButton->setEnabled(_nWindowsDisplayed > 1);
_addWindowButton->setEnabled(_nWindowsDisplayed != _nMaxWindows);
for (std::shared_ptr<WindowControl> w : _windowControl) {
w->showWindowLabel(_nWindowsDisplayed > 1);
}
_monBox->setNumWindowsDisplayed(_nWindowsDisplayed);
}
void DisplayWindowUnion::initializeWindowControl() {
if (_nWindowsAllocated < _nMaxWindows) {
unsigned int monitorNumForThisWindow = 0;
if (_nMaxWindows > 3 && _nWindowsAllocated >= 2) {
monitorNumForThisWindow = 1;
}
_windowControl.push_back(
std::make_shared<WindowControl>(
monitorNumForThisWindow,
_nWindowsAllocated,
_monitorResolutions,
_winColors[_nWindowsAllocated],
this
)
);
_windowControl.back()->setWindowChangeCallback(
[this](int monIndex, int winIndex, const QRectF& newDims) {
_monBox->windowDimensionsChanged(monIndex, winIndex, newDims);
}
);
_windowControl.back()->setWebGuiChangeCallback(
[this](unsigned int winIndex) {
for (unsigned int w = 0; w < _nMaxWindows; ++w) {
if (w != winIndex) {
_windowControl[w]->uncheckWebGuiOption();
}
}
}
);
_monBox->mapWindowResolutionToWidgetCoordinates(
monitorNumForThisWindow,
_nWindowsAllocated,
_windowControl.back()->dimensions()
);
_nWindowsAllocated++;
}
}

View File

@@ -0,0 +1,291 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/filesupport.h"
FileSupport::FileSupport(QVBoxLayout* parentLayout,
UserConfigurationElements& cfgElements,
SgctConfigElements& sgctElements,
std::function<void(bool)> finishedCallback)
: _displayWidget(cfgElements.display)
, _orientationWidget(cfgElements.orientation)
, _monitors(cfgElements.monitorList)
, _cluster(sgctElements.cluster)
, _windowList(sgctElements.windowList)
, _finishedCallback(finishedCallback)
, _userConfigPath(cfgElements.configSavePath)
{
QVBoxLayout* layoutFullVertical = new QVBoxLayout;
_saveButton = new QPushButton("Save As");
_saveButton->setToolTip("Save configuration changes (opens file chooser dialog)");
_saveButton->setFocusPolicy(Qt::NoFocus);
connect(_saveButton, &QPushButton::released, this, &FileSupport::save);
_cancelButton = new QPushButton("Cancel");
_cancelButton->setToolTip("Cancel changes");
_cancelButton->setFocusPolicy(Qt::NoFocus);
connect(_cancelButton, &QPushButton::released, this, &FileSupport::cancel);
_applyButton = new QPushButton("Apply Without Saving");
_applyButton->setToolTip("Apply configuration changes without saving to file");
_applyButton->setFocusPolicy(Qt::NoFocus);
connect(_applyButton, &QPushButton::released, this, &FileSupport::apply);
{
QHBoxLayout* layoutButtonBox = new QHBoxLayout;
layoutButtonBox->addStretch(1);
layoutButtonBox->addWidget(_cancelButton);
layoutButtonBox->addWidget(_saveButton);
layoutButtonBox->addWidget(_applyButton);
layoutFullVertical->addLayout(layoutButtonBox);
}
parentLayout->addLayout(layoutFullVertical);
}
void FileSupport::saveCluster() {
if (_orientationWidget) {
sgct::config::Scene initScene;
initScene.orientation = _orientationWidget->orientationValue();
_cluster.nodes.clear();
sgct::config::Node tmpNode;
tmpNode.address = "localhost";
tmpNode.port = 20401;
_cluster.nodes.push_back(tmpNode);
_cluster.masterAddress = "localhost";
_cluster.scene = std::move(initScene);
_cluster.firmSync = _orientationWidget->vsyncValue();
}
}
void FileSupport::saveUser() {
if (_orientationWidget) {
sgct::config::User user;
user.eyeSeparation = 0.065f;
user.position = {0.0f, 0.0f, 4.0f};
_cluster.users.push_back(user);
}
}
bool FileSupport::isWindowFullscreen(unsigned int monitorIdx, sgct::ivec2 wDims) {
return (_monitors[monitorIdx].width() == wDims.x &&
_monitors[monitorIdx].height() == wDims.y);
}
std::optional<unsigned int> FileSupport::findGuiWindow() {
unsigned int windowIndex = 0;
for (unsigned int w = 0; w < _displayWidget->nWindows(); ++w) {
if (_displayWidget->windowControls()[w]->isGuiWindow()) {
return std::optional<unsigned int>(windowIndex);
}
windowIndex++;
}
return std::nullopt;
}
void FileSupport::saveWindows() {
unsigned int windowIndex = 0;
for (unsigned int w = 0; w < _displayWidget->nWindows(); ++w) {
std::shared_ptr<WindowControl> wCtrl = _displayWidget->windowControls()[w];
sgct::config::Window tmpWindow = saveWindowsDimensions(wCtrl);
tmpWindow.viewports.push_back(generateViewport());
tmpWindow.viewports.back().projection = saveProjectionInformation(wCtrl);
tmpWindow.isDecorated = wCtrl->isDecorated();
tmpWindow.isFullScreen = isWindowFullscreen(
wCtrl->monitorNum(),
wCtrl->windowSize()
);
if (tmpWindow.isFullScreen) {
tmpWindow.monitor = wCtrl->monitorNum();
}
saveWindowsWebGui(windowIndex, tmpWindow);
if (!wCtrl->windowName().empty()) {
tmpWindow.name = wCtrl->windowName();
}
tmpWindow.id = windowIndex++;
_windowList.push_back(tmpWindow);
}
}
sgct::config::Viewport FileSupport::generateViewport() {
sgct::config::Viewport vp;
vp.isTracked = true;
vp.position = {0.f, 0.f};
vp.size = {1.f, 1.f};
return vp;
}
sgct::config::Window FileSupport::saveWindowsDimensions(
std::shared_ptr<WindowControl> wCtrl)
{
sgct::config::Window tmpWindow;
tmpWindow.size = wCtrl->windowSize();
tmpWindow.pos = {
_monitors[wCtrl->monitorNum()].x() + wCtrl->windowPos().x,
_monitors[wCtrl->monitorNum()].y() + wCtrl->windowPos().y,
};
return tmpWindow;
}
void FileSupport::saveWindowsWebGui(unsigned int wIdx, sgct::config::Window& win) {
win.viewports.back().isTracked = true;
std::optional<unsigned int> webGuiWindowIndex = findGuiWindow();
bool isOneOfWindowsSetAsWebGui = webGuiWindowIndex.has_value();
if (isOneOfWindowsSetAsWebGui) {
if (wIdx == webGuiWindowIndex.value()) {
win.viewports.back().isTracked = false;
win.tags.push_back("GUI");
}
win.draw2D = (wIdx == webGuiWindowIndex.value());
win.draw3D = !(win.draw2D.value());
}
}
ProjectionOptions FileSupport::saveProjectionInformation(
std::shared_ptr<WindowControl> winControl)
{
if (winControl->isSpoutSelected()) {
return saveProjectionSpout(winControl);
}
else {
return saveProjectionNoSpout(winControl);
}
}
ProjectionOptions FileSupport::saveProjectionSpout(
std::shared_ptr<WindowControl> winControl)
{
sgct::config::SpoutOutputProjection projection;
switch(winControl->projectionSelectedIndex()) {
case WindowControl::ProjectionIndeces::Fisheye:
projection.mapping
= sgct::config::SpoutOutputProjection::Mapping::Fisheye;
break;
case WindowControl::ProjectionIndeces::Equirectangular:
default:
projection.mapping
= sgct::config::SpoutOutputProjection::Mapping::Equirectangular;
break;
}
projection.quality = winControl->qualitySelectedValue();
projection.mappingSpoutName = "OpenSpace";
return projection;
}
ProjectionOptions FileSupport::saveProjectionNoSpout(
std::shared_ptr<WindowControl> winControl)
{
switch(winControl->projectionSelectedIndex()) {
case WindowControl::ProjectionIndeces::Fisheye:
{
sgct::config::FisheyeProjection projection;
projection.quality = winControl->qualitySelectedValue();
projection.fov = 180.f;
projection.tilt = 0.f;
return projection;
}
break;
case WindowControl::ProjectionIndeces::SphericalMirror:
{
sgct::config::SphericalMirrorProjection projection;
projection.quality = winControl->qualitySelectedValue();
return projection;
}
break;
case WindowControl::ProjectionIndeces::Cylindrical:
{
sgct::config::CylindricalProjection projection;
projection.quality = winControl->qualitySelectedValue();
projection.heightOffset = winControl->heightOffset();
return projection;
}
break;
case WindowControl::ProjectionIndeces::Equirectangular:
{
sgct::config::EquirectangularProjection projection;
projection.quality = winControl->qualitySelectedValue();
return projection;
}
break;
case WindowControl::ProjectionIndeces::Planar:
default:
{
// The negative values for left & down are according to sgct's convention
sgct::config::PlanarProjection projection;
projection.fov.right = winControl->fovH() / 2.0;
projection.fov.left = -projection.fov.right;
projection.fov.up = winControl->fovV() / 2.0;
projection.fov.down = -projection.fov.up;
return projection;
}
break;
}
}
std::string FileSupport::saveFilename() {
return _saveTarget;
}
void FileSupport::save() {
QString fileName = QFileDialog::getSaveFileName(
this,
"Save Window Configuration File",
QString::fromStdString(_userConfigPath),
"Window Configuration (*.json);;(*.json)",
nullptr
#ifdef __linux__
, QFileDialog::DontUseNativeDialog
#endif
);
if (fileName.length() != 0) {
_saveTarget = fileName.toStdString();
saveConfigToSgctFormat();
_finishedCallback(true);
}
}
void FileSupport::cancel() {
_finishedCallback(false);
}
void FileSupport::apply() {
std::string userCfgTempDir = _userConfigPath;
if (userCfgTempDir.back() != '/') {
userCfgTempDir += "/";
}
userCfgTempDir += "temp";
if (!std::filesystem::is_directory(userCfgTempDir)) {
std::filesystem::create_directories(absPath(userCfgTempDir));
}
_saveTarget = userCfgTempDir + "/" + "apply-without-saving.json";
saveConfigToSgctFormat();
_finishedCallback(true);
}
void FileSupport::saveConfigToSgctFormat() {
saveCluster();
saveWindows();
saveUser();
}

View File

@@ -0,0 +1,255 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/monitorbox.h"
constexpr float MarginFractionOfWidgetSize = 0.05f;
MonitorBox::MonitorBox(QRect widgetDims, std::vector<QRect> monitorResolution,
unsigned int nWindows, const std::array<QColor, 4>& winColors)
: _monitorWidgetSize(widgetDims)
, _monitorResolution(monitorResolution)
, _nWindows(nWindows)
, _colorsForWindows(winColors)
{
_nMonitors = static_cast<unsigned int>(monitorResolution.size());
_showLabel = (_nMonitors > 1);
determineMonitorArrangement();
this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
float borderMargin = MarginFractionOfWidgetSize * 2.f;
if (_monitorArrangementAspectRatio > 1.0) {
borderMargin *= _monitorWidgetSize.width();
_monitorWidgetSize.setHeight(_monitorWidgetSize.width()
/ _monitorArrangementAspectRatio + borderMargin);
}
else {
borderMargin *= _monitorWidgetSize.height();
_monitorWidgetSize.setWidth(_monitorWidgetSize.height()
* _monitorArrangementAspectRatio + borderMargin);
}
this->setFixedSize(_monitorWidgetSize.width(), _monitorWidgetSize.height());
mapMonitorResolutionToWidgetCoordinates();
}
void MonitorBox::paintEvent(QPaintEvent* event) {
Q_UNUSED(event)
QPainter painter(this);
QPen pen = painter.pen();
painter.setPen(pen);
paintWidgetBorder(painter, width(), height());
//Draw window out-of-bounds region(s) first
for (unsigned int i = 0; i < _nWindows; ++i) {
paintWindowBeyondBounds(painter, i);
}
//Draw & fill monitors over the out-of-bounds regions
paintMonitorBackgrounds(painter);
//Draw window number(s) first for darker contrast, then window(s) over both
//out-of-bounds and monitors
for (unsigned int i = 0; i < _nWindows; ++i) {
paintWindowNumber(painter, i);
}
for (unsigned int i = 0; i < _nWindows; ++i) {
paintWindow(painter, i);
}
}
void MonitorBox::paintWidgetBorder(QPainter& painter, int width, int height) {
constexpr int Radius = 10;
painter.setPen(QPen(Qt::gray, 4));
painter.drawRoundedRect(0, 0, width - 1, height - 1, Radius, Radius);
}
void MonitorBox::paintMonitorBackgrounds(QPainter& painter) {
painter.setPen(QPen(Qt::black, 2));
QFont f("Arial");
f.setPixelSize(24);
painter.setFont(f);
for (unsigned int i = 0; i < _nMonitors; ++i) {
if (i <= _monitorDimensionsScaled.size()) {
painter.drawRect(_monitorDimensionsScaled[i]);
QColor fillColor("#DDDDDD");
QBrush brush(fillColor);
brush.setStyle(Qt::SolidPattern);
painter.fillRect(_monitorDimensionsScaled[i], brush);
if (_showLabel) {
QPointF textPos = QPointF(
_monitorDimensionsScaled[i].left() + 4,
_monitorDimensionsScaled[i].top() + 24
);
if (i == 0) {
painter.drawText(textPos, "Primary");
}
}
}
}
}
void MonitorBox::paintWindowBeyondBounds(QPainter& painter, unsigned int winIdx) {
painter.setBrush(Qt::BDiagPattern);
setPenSpecificToWindow(painter, winIdx, false);
if (winIdx <= _windowRendering.size()) {
painter.drawRect(_windowRendering[winIdx]);
}
setPenSpecificToWindow(painter, winIdx, true);
painter.setBrush(Qt::NoBrush);
}
void MonitorBox::paintWindow(QPainter& painter, size_t winIdx) {
setPenSpecificToWindow(painter, static_cast<unsigned int>(winIdx), true);
if (winIdx <= _windowRendering.size()) {
painter.drawRect(_windowRendering[winIdx]);
QColor fillColor = _colorsForWindows[winIdx];
fillColor.setAlpha(_alphaWindowOpacity);
QBrush brush(fillColor);
brush.setStyle(Qt::SolidPattern);
painter.fillRect(_windowRendering[winIdx], brush);
}
}
void MonitorBox::paintWindowNumber(QPainter& painter, unsigned int winIdx) {
QPointF textPos = QPointF(_windowRendering[winIdx].left() + 5,
_windowRendering[winIdx].bottom() - 5);
textPos.setX(std::clamp(textPos.x(), 0.0, _monitorWidgetSize.width() - 10));
textPos.setY(std::clamp(textPos.y(), 20.0, _monitorWidgetSize.height()));
painter.drawText(textPos, QString::fromStdString(std::to_string(winIdx + 1)));
}
void MonitorBox::setPenSpecificToWindow(QPainter& painter, unsigned int windowIdx,
bool visibleBorder)
{
int penWidth = (visibleBorder) ? 1 : -1;
painter.setPen(QPen(_colorsForWindows[windowIdx], penWidth));
}
void MonitorBox::windowDimensionsChanged(unsigned int mIdx, unsigned int wIdx,
const QRectF& newDimensions)
{
mapWindowResolutionToWidgetCoordinates(mIdx, wIdx, newDimensions);
}
void MonitorBox::determineMonitorArrangement() {
for (const QRect& m : _monitorResolution) {
if (m.x() < _negativeCorrectionOffsets.x()) {
_negativeCorrectionOffsets.setX(m.x());
}
if (m.y() < _negativeCorrectionOffsets.y()) {
_negativeCorrectionOffsets.setY(m.y());
}
}
for (const QRect& m : _monitorResolution) {
if ((m.x() + m.width() - _negativeCorrectionOffsets.x())
> _monitorArrangementDimensions.width())
{
_monitorArrangementDimensions.setWidth(
m.x() + m.width() - _negativeCorrectionOffsets.x());
}
if ((m.y() + m.height() - _negativeCorrectionOffsets.y())
> _monitorArrangementDimensions.height())
{
_monitorArrangementDimensions.setHeight(
m.y() + m.height() - _negativeCorrectionOffsets.y());
}
}
_monitorArrangementAspectRatio = _monitorArrangementDimensions.width()
/ _monitorArrangementDimensions.height();
}
void MonitorBox::mapMonitorResolutionToWidgetCoordinates() {
if (_monitorArrangementAspectRatio >= 1.0) {
computeScaledResolutionLandscape(
_monitorArrangementAspectRatio,
_monitorArrangementDimensions.width()
);
}
else {
computeScaledResolutionPortrait(
_monitorArrangementAspectRatio,
_monitorArrangementDimensions.height()
);
}
for (size_t m = 0; m < _monitorResolution.size(); ++m) {
_monitorDimensionsScaled.push_back({
_monitorOffsets[m].width(),
_monitorOffsets[m].height(),
_monitorResolution[m].width() * _monitorScaleFactor,
_monitorResolution[m].height() * _monitorScaleFactor,
});
}
update();
}
void MonitorBox::computeScaledResolutionLandscape(float aspectRatio, float maxWidth) {
_marginWidget = _monitorWidgetSize.width() * MarginFractionOfWidgetSize;
float virtualWidth = _monitorWidgetSize.width()
* (1.0 - MarginFractionOfWidgetSize * 2.0);
_monitorScaleFactor = virtualWidth / maxWidth;
float newHeight = virtualWidth / aspectRatio;
for (size_t m = 0; m < _monitorResolution.size(); ++m) {
_monitorOffsets.push_back({
_marginWidget + (_monitorResolution[m].x() - _negativeCorrectionOffsets.x())
* _monitorScaleFactor,
_marginWidget + (_monitorWidgetSize.height() - newHeight - _marginWidget) / 4.0
+ (_monitorResolution[m].y() - _negativeCorrectionOffsets.y())
* _monitorScaleFactor
});
}
}
void MonitorBox::computeScaledResolutionPortrait(float aspectRatio, float maxHeight) {
_marginWidget = _monitorWidgetSize.height() * MarginFractionOfWidgetSize;
float virtualHeight = _monitorWidgetSize.height()
* (1.0 - MarginFractionOfWidgetSize * 2.0);
_monitorScaleFactor = virtualHeight / maxHeight;
float newWidth = virtualHeight * aspectRatio;
for (size_t m = 0; m < _monitorResolution.size(); ++m) {
_monitorOffsets.push_back({
_marginWidget + (_monitorWidgetSize.width() - newWidth - _marginWidget) / 4.0
+ (_monitorResolution[m].x() - _negativeCorrectionOffsets.x())
* _monitorScaleFactor,
_marginWidget + (_monitorResolution[m].y() - _negativeCorrectionOffsets.y())
* _monitorScaleFactor
});
}
}
void MonitorBox::setNumWindowsDisplayed(unsigned int nWindows) {
if (_nWindows != nWindows) {
_nWindows = nWindows;
update();
}
}
void MonitorBox::mapWindowResolutionToWidgetCoordinates(unsigned int mIdx,
unsigned int wIdx,
const QRectF& winDimensions)
{
QRectF wF = winDimensions;
_windowRendering[wIdx] = {
_monitorDimensionsScaled[mIdx].x() + wF.left() * _monitorScaleFactor,
_monitorDimensionsScaled[mIdx].y() + wF.top() * _monitorScaleFactor,
wF.width() * _monitorScaleFactor,
wF.height() * _monitorScaleFactor
};
update();
}

View File

@@ -0,0 +1,73 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/orientation.h"
#include "sgctedit/orientationdialog.h"
Orientation::Orientation()
: _orientationDialog(_orientationValue, this)
{
_layoutOrientationFull = new QHBoxLayout;
{
QVBoxLayout* layoutOrientationControls = new QVBoxLayout;
QPushButton* orientationButton = new QPushButton("Global Orientation");
_checkBoxVsync = new QCheckBox("VSync All Windows", this);
_checkBoxVsync->setToolTip(
"If enabled, the server will frame lock and wait for all client nodes"
);
layoutOrientationControls->addWidget(_checkBoxVsync);
orientationButton->setToolTip(
"Opens a separate dialog for setting the pitch, "
"yaw, and roll of the camera\n(the orientation applies to all viewports)"
);
orientationButton->setFocusPolicy(Qt::NoFocus);
layoutOrientationControls->addWidget(orientationButton);
_layoutOrientationFull->addStretch(1);
_layoutOrientationFull->addLayout(layoutOrientationControls);
_layoutOrientationFull->addStretch(1);
connect(
orientationButton,
&QPushButton::released,
this,
&Orientation::orientationDialog
);
}
}
void Orientation::addControlsToParentLayout(QVBoxLayout* parentLayout) {
parentLayout->addLayout(_layoutOrientationFull);
}
void Orientation::orientationDialog() {
_orientationDialog.exec();
}
sgct::quat Orientation::orientationValue() const {
return _orientationValue;
}
bool Orientation::vsyncValue() const {
return (_checkBoxVsync->checkState() == Qt::Checked);
}

View File

@@ -0,0 +1,119 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/orientationdialog.h"
#include "sgctedit/displaywindowunion.h"
OrientationDialog::OrientationDialog(sgct::quat& orientation, QWidget* parent)
: QDialog(parent)
, _orientationValue(orientation)
{
setWindowTitle("Global Orientation");
QVBoxLayout* layoutWindow = new QVBoxLayout(this);
_linePitch = new QLineEdit;
_lineRoll = new QLineEdit;
_lineYaw = new QLineEdit;
_linePitch->setText(QString::number(_orientationValue.x));
_lineRoll->setText(QString::number(_orientationValue.z));
_lineYaw->setText(QString::number(_orientationValue.y));
{
QDoubleValidator* validatorPitch = new QDoubleValidator(-90.0, 90.0, 15);
QDoubleValidator* validatorRoll = new QDoubleValidator(-360.0, 360.0, 15);
QDoubleValidator* validatorYaw = new QDoubleValidator(-180.0, 180.0, 15);
validatorPitch->setNotation(QDoubleValidator::StandardNotation);
validatorRoll->setNotation(QDoubleValidator::StandardNotation);
validatorYaw->setNotation(QDoubleValidator::StandardNotation);
_linePitch->setValidator(validatorPitch);
_lineRoll->setValidator(validatorRoll);
_lineYaw->setValidator(validatorYaw);
}
{
QLabel* labelPitch = new QLabel;
labelPitch->setText("Pitch: ");
QHBoxLayout* layoutPitch = new QHBoxLayout;
layoutPitch->addStretch(1);
QString pitchTip = "Pitch or elevation: negative numbers tilt the camera "
"downwards; positive numbers tilt upwards.\nThe allowed range is [-90, 90]. "
"Internally, this corresponds to the x value in the quaternion.";
labelPitch->setToolTip(pitchTip);
_linePitch->setToolTip(pitchTip);
layoutPitch->addWidget(labelPitch);
layoutPitch->addWidget(_linePitch);
layoutWindow->addLayout(layoutPitch);
QLabel* labelRoll = new QLabel;
labelRoll ->setText("Roll: ");
QHBoxLayout* layoutRoll = new QHBoxLayout;
layoutRoll->addStretch(1);
QString rollTip = "Roll or bank: negative numbers rotate the camera counter-"
"clockwise; positive numbers clockwise.\nThe allowed range is [-180, 180]. "
"Internally, this corresponds to the z value in the quaternion.";
labelRoll->setToolTip(rollTip);
_lineRoll->setToolTip(rollTip);
layoutRoll->addWidget(labelRoll);
layoutRoll->addWidget(_lineRoll);
layoutWindow->addLayout(layoutRoll);
QLabel* labelYaw = new QLabel;
labelYaw ->setText("Yaw: ");
QHBoxLayout* layoutYaw = new QHBoxLayout;
layoutYaw->addStretch(1);
QString yawTip = "Yaw, heading, or azimuth: negative numbers pan the camera "
"to the left; positive numbers pan to the\nright. The allowed range is "
"[-360, 360]. Internally, this corresponds to the y value in the quaternion.";
labelYaw->setToolTip(yawTip);
_lineYaw->setToolTip(yawTip);
layoutYaw->addWidget(labelYaw);
layoutYaw->addWidget(_lineYaw);
layoutWindow->addLayout(layoutYaw);
}
{
QHBoxLayout* layoutButtonBox = new QHBoxLayout;
QPushButton* buttonSave = new QPushButton("OK");
buttonSave->setToolTip("Save global orientation changes");
buttonSave->setFocusPolicy(Qt::NoFocus);
layoutButtonBox->addStretch(1);
layoutButtonBox->addWidget(buttonSave);
QPushButton* buttonCancel = new QPushButton("Cancel");
buttonCancel->setToolTip("Cancel global orientation changes");
buttonCancel->setFocusPolicy(Qt::NoFocus);
layoutButtonBox->addWidget(buttonCancel);
layoutButtonBox->addStretch(1);
connect(buttonSave, &QPushButton::released, this, &OrientationDialog::ok);
connect(buttonCancel, &QPushButton::released, this, &OrientationDialog::cancel);
layoutWindow->addLayout(layoutButtonBox);
}
}
void OrientationDialog::ok() {
_orientationValue.x = _linePitch->text().toFloat() / 180.0 * glm::pi<float>();
_orientationValue.y = _lineYaw->text().toFloat() / 180.0 * glm::pi<float>();
_orientationValue.z = _lineRoll->text().toFloat() / 180.0 * glm::pi<float>();
_orientationValue.w = 1.0;
accept();
}
void OrientationDialog::cancel() {
reject();
}

View File

@@ -0,0 +1,139 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/sgctedit.h"
#include <QFileDialog>
SgctEdit::SgctEdit(QWidget* parent, std::vector<sgct::config::Window>& windowList,
sgct::config::Cluster& cluster, const QList<QScreen*>& screenList,
const std::string userConfigPath)
: QDialog(parent)
, _cluster(cluster)
, _windowList(windowList)
, _userConfigPath(userConfigPath)
{
systemMonitorConfiguration(screenList);
setWindowTitle("Window Configuration Editor");
createWidgets();
}
void SgctEdit::systemMonitorConfiguration(const QList<QScreen*>& screenList) {
size_t nScreensManaged = std::min(static_cast<int>(screenList.length()), 2);
for (unsigned int s = 0; s < static_cast<unsigned int>(nScreensManaged); ++s) {
int actualWidth = std::max(
screenList[s]->size().width(),
screenList[s]->availableGeometry().width()
);
int actualHeight = std::max(
screenList[s]->size().height(),
screenList[s]->availableGeometry().height()
);
_monitorSizeList.push_back({
screenList[s]->availableGeometry().x(),
screenList[s]->availableGeometry().y(),
actualWidth,
actualHeight
});
}
_nMaxWindows = (_monitorSizeList.size() == 1) ? 3 : 4;
}
void SgctEdit::createWidgets() {
QVBoxLayout* layoutMainV = new QVBoxLayout(this);
QHBoxLayout* layoutMainH = new QHBoxLayout;
_orientationWidget = new Orientation();
{
_monBox = std::make_shared<MonitorBox>(
_monitorWidgetSize,
_monitorSizeList,
_nMaxWindows,
_colorsForWindows
);
QHBoxLayout* layoutMonBox = new QHBoxLayout;
layoutMonBox->addStretch(1);
layoutMonBox->addWidget(_monBox.get());
layoutMonBox->addStretch(1);
layoutMainV->addLayout(layoutMonBox);
addDisplayLayout(layoutMainH);
}
{
layoutMainV->addLayout(layoutMainH);
_orientationWidget->addControlsToParentLayout(layoutMainV);
QFrame* bottomBorder = new QFrame();
bottomBorder->setFrameShape(QFrame::HLine);
layoutMainV->addWidget(bottomBorder);
SgctConfigElements sgctCfg = {_windowList, _cluster};
UserConfigurationElements userCfg = {
_monitorSizeList,
_displayWidget,
_orientationWidget,
_userConfigPath
};
_fileSupportWidget = new FileSupport(
layoutMainV,
userCfg,
sgctCfg,
[this](bool accepted) {
if (accepted) {
_saveSelected = true;
accept();
}
else {
reject();
}
}
);
}
}
void SgctEdit::addDisplayLayout(QHBoxLayout* layout) {
_displayLayout = new QVBoxLayout;
_displayWidget = std::make_shared<DisplayWindowUnion>(
_monBox,
_monitorSizeList,
_nMaxWindows,
_colorsForWindows
);
_displayFrame = new QFrame;
_displayLayout->addWidget(_displayWidget.get());
_displayFrame->setLayout(_displayLayout);
_displayFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
layout->addWidget(_displayFrame);
}
bool SgctEdit::wasSaved() const {
return _saveSelected;
}
std::string SgctEdit::saveFilename() {
return _fileSupportWidget->saveFilename();
}
SgctEdit::~SgctEdit() {
delete _orientationWidget;
delete _fileSupportWidget;
delete _displayLayout;
}

View File

@@ -0,0 +1,677 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/windowcontrol.h"
#include <ghoul/fmt.h>
#include "sgctedit/displaywindowunion.h"
#include "sgctedit/monitorbox.h"
const std::string ProjectionTypeNames[5] = {"Planar", "Fisheye", "Spherical Mirror",
"Cylindrical", "Equirectangular"};
QList<QString> ProjectionTypes = {
QString::fromStdString(ProjectionTypeNames[static_cast<int>(
WindowControl::ProjectionIndeces::Planar)]),
QString::fromStdString(ProjectionTypeNames[static_cast<int>(
WindowControl::ProjectionIndeces::Fisheye)]),
QString::fromStdString(ProjectionTypeNames[static_cast<int>(
WindowControl::ProjectionIndeces::SphericalMirror)]),
QString::fromStdString(ProjectionTypeNames[static_cast<int>(
WindowControl::ProjectionIndeces::Cylindrical)]),
QString::fromStdString(ProjectionTypeNames[static_cast<int>(
WindowControl::ProjectionIndeces::Equirectangular)])
};
const QList<QString> QualityTypes = {
"Low (256)",
"Medium (512)",
"High (1K)",
"1.5K (1536)",
"2K (2048)",
"4K (4096)",
"8K (8192)",
"16K (16384)",
"32K (32768)",
"64K (65536)"
};
WindowControl::WindowControl(unsigned int monitorIndex, unsigned int windowIndex,
std::vector<QRect>& monitorDims,
const QColor& winColor, QWidget *parent)
: QWidget(parent)
, _monIndex(monitorIndex)
, _monIndexDefault(monitorIndex)
, _index(windowIndex)
, _monitorResolutions(monitorDims)
, _colorForWindow(winColor)
{
Q_INIT_RESOURCE(resources);
_nMonitors = static_cast<unsigned int>(_monitorResolutions.size());
createWidgets(parent);
resetToDefaults();
}
WindowControl::~WindowControl() {
delete _layoutFullWindow;
}
void WindowControl::resetToDefaults() {
determineIdealWindowSize();
_windowName->setText("");
_monIndex = _monIndexDefault;
if (_nMonitors > 1) {
_comboMonitorSelect->setCurrentIndex(_monIndexDefault);
}
_checkBoxWindowDecor->setCheckState(Qt::CheckState::Checked);
_checkBoxWebGui->setCheckState(Qt::CheckState::Unchecked);
onWebGuiSelection(_checkBoxWebGui->checkState());
_checkBoxSpoutOutput->setCheckState(Qt::CheckState::Unchecked);
onSpoutSelection(_checkBoxSpoutOutput->checkState());
_comboProjection->setCurrentIndex(static_cast<int>(ProjectionIndeces::Planar));
onProjectionChanged(_comboProjection->currentIndex());
_lineFovH->setText(QString::number(_defaultFovH));
_lineFovV->setText(QString::number(_defaultFovV));
_lineHeightOffset->setText(QString::number(_defaultHeightOffset));
_comboQuality->setCurrentIndex(2);
if (_windowChangeCallback) {
_windowChangeCallback(_monIndex, _index, _windowDims);
}
}
void WindowControl::determineIdealWindowSize() {
constexpr float idealAspectRatio = 16.f / 9.f;
constexpr float idealScaleVerticalLines = 2.f / 3.f;
const unsigned int primaryMonitorIdx = 0;
_windowDims = defaultWindowSizes[_index];
_offsetX->setText(QString::number(_windowDims.x()));
_offsetY->setText(QString::number(_windowDims.y()));
float newHeight = static_cast<float>(_monitorResolutions[primaryMonitorIdx].height())
* idealScaleVerticalLines;
float newWidth = newHeight * idealAspectRatio;
_windowDims.setHeight(newHeight);
_windowDims.setWidth(newWidth);
_sizeX->setText(QString::number(static_cast<int>(newWidth)));
_sizeY->setText(QString::number(static_cast<int>(newHeight)));
}
QString WindowControl::resolutionLabelText(QRect resolution) {
return QString::number(resolution.width()) + "x" +
QString::number(resolution.height());
}
void WindowControl::createWidgets(QWidget* parent) {
_windowName = new QLineEdit(parent);
_sizeX = new QLineEdit(parent);
_sizeY = new QLineEdit(parent);
_offsetX = new QLineEdit(parent);
_offsetY = new QLineEdit(parent);
_labelQuality = new QLabel;
_labelFovH = new QLabel;
_labelFovV = new QLabel;
_labelHeightOffset = new QLabel;
_buttonLockAspectRatio = new QPushButton(parent);
_buttonLockFov = new QPushButton(parent);
_lockIcon.addPixmap(QPixmap(":/images/outline_locked.png"));
_unlockIcon.addPixmap(QPixmap(":/images/outline_unlocked.png"));
_buttonLockAspectRatio->setIcon(_unlockIcon);
_buttonLockFov->setIcon(_lockIcon);
{
QIntValidator* validatorSizeX = new QIntValidator(10, _maxWindowSizePixels);
QIntValidator* validatorSizeY = new QIntValidator(10, _maxWindowSizePixels);
QIntValidator* validatorOffsetX = new QIntValidator(
-_maxWindowSizePixels,
_maxWindowSizePixels
);
QIntValidator* validatorOffsetY = new QIntValidator(
-_maxWindowSizePixels,
_maxWindowSizePixels
);
_sizeX->setValidator(validatorSizeX);
_sizeY->setValidator(validatorSizeY);
_offsetX->setValidator(validatorOffsetX);
_offsetY->setValidator(validatorOffsetY);
}
if (_nMonitors > 1) {
_comboMonitorSelect = new QComboBox(this);
for (unsigned int i = 0; i < _nMonitors; ++i) {
_monitorNames[i] += " (" + resolutionLabelText(_monitorResolutions[i]) + ")";
}
_comboMonitorSelect->addItems(_monitorNames);
_comboMonitorSelect->setCurrentIndex(_monIndexDefault);
}
_fullscreenButton = new QPushButton(this);
_fullscreenButton->setText("Set to Fullscreen");
_checkBoxWindowDecor = new QCheckBox("Window Decoration", this);
_checkBoxWindowDecor->setCheckState(Qt::CheckState::Checked);
_checkBoxWebGui = new QCheckBox("WebGUI only this window", this);
_checkBoxSpoutOutput = new QCheckBox("Spout Output", this);
_comboProjection = new QComboBox(this);
_comboProjection->addItems(ProjectionTypes);
_comboQuality = new QComboBox(this);
_comboQuality->addItems(QualityTypes);
{
_lineFovH = new QLineEdit(QString::number(_defaultFovH), parent);
_lineFovV = new QLineEdit(QString::number(_defaultFovV), parent);
QDoubleValidator* validatorFovH = new QDoubleValidator(-180.0, 180.0, 10);
_lineFovH->setValidator(validatorFovH);
QDoubleValidator* validatorFovV = new QDoubleValidator(-90.0, 90.0, 10);
_lineFovV->setValidator(validatorFovV);
_lineHeightOffset = new QLineEdit(QString::number(_defaultHeightOffset), parent);
QDoubleValidator* validatorHtOff= new QDoubleValidator(-1000000.0, 1000000.0, 12);
_lineHeightOffset->setValidator(validatorHtOff);
}
connect(_sizeX, &QLineEdit::textChanged, this, &WindowControl::onSizeXChanged);
connect(_sizeY, &QLineEdit::textChanged, this, &WindowControl::onSizeYChanged);
connect(_offsetX, &QLineEdit::textChanged, this, &WindowControl::onOffsetXChanged);
connect(_offsetY, &QLineEdit::textChanged, this, &WindowControl::onOffsetYChanged);
if (_nMonitors > 1) {
connect(
_comboMonitorSelect,
qOverload<int>(&QComboBox::currentIndexChanged),
this,
&WindowControl::onMonitorChanged
);
}
connect(
_comboProjection,
qOverload<int>(&QComboBox::currentIndexChanged),
this,
&WindowControl::onProjectionChanged
);
connect(
_checkBoxSpoutOutput,
&QCheckBox::stateChanged,
this,
&WindowControl::onSpoutSelection
);
connect(
_checkBoxWebGui,
&QCheckBox::stateChanged,
this,
&WindowControl::onWebGuiSelection
);
connect(
_fullscreenButton,
&QPushButton::released,
this,
&WindowControl::onFullscreenClicked
);
connect(
_buttonLockAspectRatio,
&QPushButton::released,
this,
&WindowControl::onAspectRatioLockClicked
);
connect(
_buttonLockFov,
&QPushButton::released,
this,
&WindowControl::onFovLockClicked
);
}
QVBoxLayout* WindowControl::initializeLayout() {
_layoutFullWindow = new QVBoxLayout;
//Window size
QVBoxLayout* layoutWindowCtrl = new QVBoxLayout;
_labelWinNum = new QLabel;
_labelWinNum->setText("Window " + QString::number(_index + 1));
QString colorStr = QString::fromStdString(
fmt::format("QLabel {{ color : #{:02x}{:02x}{:02x}; }}",
_colorForWindow.red(), _colorForWindow.green(), _colorForWindow.blue()));
_labelWinNum->setStyleSheet(colorStr);
QHBoxLayout* layoutWinNum = new QHBoxLayout;
layoutWinNum->addStretch(1);
layoutWinNum->addWidget(_labelWinNum);
layoutWinNum->addStretch(1);
layoutWindowCtrl->addLayout(layoutWinNum);
{
QHBoxLayout* layoutName = new QHBoxLayout;
QString tip("Enter a name for the window (displayed in title bar)");
QLabel* labelName = new QLabel(this);
labelName->setText("Name: ");
labelName->setToolTip(tip);
_windowName->setFixedWidth(160);
_windowName->setToolTip(tip);
layoutName->addWidget(labelName);
layoutName->addWidget(_windowName);
layoutName->addStretch(1);
layoutWindowCtrl->addLayout(layoutName);
}
if (_nMonitors > 1) {
QHBoxLayout* layoutMonitorNum = new QHBoxLayout;
QLabel* labelLocation = new QLabel(this);
labelLocation->setText("Monitor: ");
QString tip("Select monitor where this window is located");
labelLocation->setToolTip(tip);
_comboMonitorSelect->setToolTip(tip);
layoutMonitorNum->addWidget(labelLocation);
layoutMonitorNum->addWidget(_comboMonitorSelect);
layoutMonitorNum->addStretch(1);
layoutWindowCtrl->addLayout(layoutMonitorNum);
}
_sizeX->setFixedWidth(_lineEditWidthFixedWinSize);
_sizeY->setFixedWidth(_lineEditWidthFixedWinSize);
{
QLabel* labelSize = new QLabel(this);
QLabel* labelDelim = new QLabel(this);
QLabel* labelUnit = new QLabel(this);
QHBoxLayout* layoutSize = new QHBoxLayout;
labelSize->setToolTip("Enter window width & height in pixels");
_sizeX->setToolTip("Enter window width (pixels)");
_sizeY->setToolTip("Enter window height (pixels)");
_buttonLockAspectRatio->setFocusPolicy(Qt::NoFocus);
_buttonLockAspectRatio->setToolTip("Locks/Unlocks size aspect ratio");
layoutSize->addWidget(labelSize);
labelSize->setText("Size:");
labelSize->setFixedWidth(55);
layoutSize->addWidget(_sizeX);
layoutSize->addWidget(labelDelim);
layoutSize->addWidget(_sizeY);
layoutSize->addWidget(labelUnit);
layoutSize->addWidget(_buttonLockAspectRatio);
layoutSize->addStretch(1);
labelDelim->setText("x");
labelDelim->setFixedWidth(9);
labelUnit->setText(" px");
layoutWindowCtrl->addLayout(layoutSize);
}
_offsetX->setFixedWidth(_lineEditWidthFixedWinSize);
_offsetY->setFixedWidth(_lineEditWidthFixedWinSize);
{
QLabel* labelOffset = new QLabel(this);
QLabel* labelComma = new QLabel(this);
QLabel* labelUnit = new QLabel(this);
QHBoxLayout* layoutOffset = new QHBoxLayout;
std::string baseTip = "Enter {} location of window's upper left "
"corner from monitor's {} (pixels)";
labelOffset->setToolTip(QString::fromStdString(fmt::format(
baseTip, "x,y", "upper-left corner origin")));
_offsetX->setToolTip(QString::fromStdString(fmt::format(
baseTip, "x", "left side")));
_offsetY->setToolTip(QString::fromStdString(fmt::format(
baseTip, "y", "top edge")));
layoutOffset->addWidget(labelOffset);
labelOffset->setText("Offset:");
labelOffset->setFixedWidth(55);
layoutOffset->addWidget(_offsetX);
layoutOffset->addWidget(labelComma);
layoutOffset->addWidget(_offsetY);
layoutOffset->addWidget(labelUnit);
layoutOffset->addStretch(1);
labelComma->setText(",");
labelComma->setFixedWidth(9);
labelUnit->setText(" px");
layoutWindowCtrl->addLayout(layoutOffset);
}
{
QHBoxLayout* layoutCheckboxesFull1 = new QHBoxLayout;
QVBoxLayout* layoutCheckboxesFull2 = new QVBoxLayout;
QHBoxLayout* layoutFullscreenButton = new QHBoxLayout;
_fullscreenButton->setToolTip("If enabled, the window will be created in an "
"exclusive fullscreen mode. The size of this\nwindow will be set to the "
"screen resolution, and the window decoration automatically disabled.");
_fullscreenButton->setFocusPolicy(Qt::NoFocus);
layoutFullscreenButton->addWidget(_fullscreenButton);
layoutFullscreenButton->addStretch(1);
layoutCheckboxesFull2->addLayout(layoutFullscreenButton);
QHBoxLayout* layoutCBoxWindowDecor = new QHBoxLayout;
_checkBoxWindowDecor->setToolTip("If enabled, the window will not have a border "
"frame or title bar, and no\n controls for minimizing/maximizing, "
"resizing, or closing the window.");
layoutCBoxWindowDecor->addWidget(_checkBoxWindowDecor);
layoutCBoxWindowDecor->addStretch(1);
layoutCheckboxesFull2->addLayout(layoutCBoxWindowDecor);
QHBoxLayout* _layoutCBoxWebGui= new QHBoxLayout;
_checkBoxWebGui->setToolTip("If enabled, the window will be dedicated solely to "
"displaying the GUI controls, and will not\nrender any 3D content. All other "
"window(s) will render in 3D but will not have GUI controls.");
_layoutCBoxWebGui->addWidget(_checkBoxWebGui);
_layoutCBoxWebGui->addStretch(1);
layoutCheckboxesFull2->addLayout(_layoutCBoxWebGui);
QVBoxLayout* layoutProjectionGroup = new QVBoxLayout;
QHBoxLayout* layoutComboProjection = new QHBoxLayout;
_comboProjection->setToolTip("Select from the supported window projection types");
layoutComboProjection->addWidget(_comboProjection);
layoutComboProjection->addWidget(_buttonLockFov);
_buttonLockFov->setToolTip("Locks and scales the Horizontal & Vertical F.O.V. "
"to the ideal settings based on aspect ratio.");
_buttonLockFov->setFocusPolicy(Qt::NoFocus);
layoutComboProjection->addStretch(1);
layoutProjectionGroup->addLayout(layoutComboProjection);
QFrame* borderProjectionGroup = new QFrame;
borderProjectionGroup->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
borderProjectionGroup->setLayout(layoutProjectionGroup);
borderProjectionGroup->setVisible(true);
QHBoxLayout* layoutCBoxSpoutOutput= new QHBoxLayout;
QString spoutTip = "This projection method provides the ability to share the "
"reprojected image using the Spout library.\nThis library only supports the "
"Windows operating system. Spout makes it possible to make the rendered\n"
"images available to other real-time applications on the same machine for "
"further processing.\nThe SpoutOutputProjection option can work with either "
"Fisheye or Equirectangular projection.";
_checkBoxSpoutOutput->setToolTip(spoutTip);
layoutCBoxSpoutOutput->addWidget(_checkBoxSpoutOutput);
layoutCBoxSpoutOutput->addStretch(1);
layoutProjectionGroup->addLayout(layoutCBoxSpoutOutput);
QHBoxLayout* layoutComboQuality = new QHBoxLayout;
_labelQuality->setText("Quality:");
QString qualityTip = "Determines the pixel resolution of the projection "
"rendering. The higher resolution,\nthe better the rendering quality, but at "
"the expense of increased rendering times.";
_labelQuality->setToolTip(qualityTip);
_comboQuality->setToolTip(qualityTip);
layoutComboQuality->addWidget(_labelQuality);
layoutComboQuality->addWidget(_comboQuality);
layoutComboQuality->addStretch(1);
layoutProjectionGroup->addLayout(layoutComboQuality);
QHBoxLayout* layoutFovH = new QHBoxLayout;
_labelFovH->setText("Horizontal FOV:");
QString hfovTip = "The total horizontal field of view of the viewport (degrees). "
"Internally,\nthe values for 'left' & 'right' will each be half this value.";
_labelFovH->setToolTip(hfovTip);
_lineFovH->setToolTip(hfovTip);
layoutFovH->addWidget(_labelFovH);
layoutFovH->addStretch(1);
layoutFovH->addWidget(_lineFovH);
QHBoxLayout* layoutFovV = new QHBoxLayout;
_labelFovV->setText("Vertical FOV:");
QString vfovTip = "The total vertical field of view of the viewport (degrees). "
"Internally,\nthe values for 'up' & 'down' will each be half this value.";
_labelFovV->setToolTip(vfovTip);
_lineFovV->setToolTip(vfovTip);
layoutFovV->addWidget(_labelFovV);
layoutFovV->addStretch(1);
layoutFovV->addWidget(_lineFovV);
_lineFovH->setFixedWidth(_lineEditWidthFixedFov);
_lineFovV->setFixedWidth(_lineEditWidthFixedFov);
_lineFovH->setEnabled(false);
_lineFovV->setEnabled(false);
layoutProjectionGroup->addLayout(layoutFovH);
layoutProjectionGroup->addLayout(layoutFovV);
QHBoxLayout* layoutHeightOffset = new QHBoxLayout;
_labelHeightOffset->setText("Height Offset:");
QString heightTip = "Offsets the height from which the cylindrical projection "
"is generated.\nThis is, in general, only necessary if the user position is "
"offset and\ncountering that offset is desired in order to continue producing"
"\na 'standard' cylindrical projection.";
_labelHeightOffset->setToolTip(heightTip);
_lineHeightOffset->setToolTip(heightTip);
layoutHeightOffset->addWidget(_labelHeightOffset);
layoutHeightOffset->addWidget(_lineHeightOffset);
layoutHeightOffset->addStretch(1);
layoutProjectionGroup->addLayout(layoutHeightOffset);
layoutCheckboxesFull2->addWidget(borderProjectionGroup);
layoutCheckboxesFull1->addLayout(layoutCheckboxesFull2);
layoutCheckboxesFull1->addStretch(1);
layoutWindowCtrl->addLayout(layoutCheckboxesFull1);
}
layoutWindowCtrl->addStretch(1);
_layoutFullWindow->addLayout(layoutWindowCtrl);
_comboProjection->setCurrentIndex(0);
onProjectionChanged(static_cast<unsigned int>(ProjectionIndeces::Planar));
_comboQuality->setCurrentIndex(2);
return _layoutFullWindow;
}
void WindowControl::showWindowLabel(bool show) {
_labelWinNum->setVisible(show);
}
void WindowControl::onSizeXChanged(const QString& newText) {
_windowDims.setWidth(newText.toInt());
if (_aspectRatioLocked) {
int updatedHeight = _windowDims.width() / _aspectRatioSize;
_sizeY->blockSignals(true);
_sizeY->setText(QString::number(updatedHeight));
_sizeY->blockSignals(false);
_windowDims.setHeight(updatedHeight);
}
if (_windowChangeCallback) {
_windowChangeCallback(_monIndex, _index, _windowDims);
}
if (_FovLocked) {
updatePlanarLockedFov();
}
}
void WindowControl::onSizeYChanged(const QString& newText) {
_windowDims.setHeight(newText.toInt());
if (_aspectRatioLocked) {
int updatedWidth = _windowDims.height() * _aspectRatioSize;
_sizeX->blockSignals(true);
_sizeX->setText(QString::number(updatedWidth));
_sizeX->blockSignals(false);
_windowDims.setWidth(updatedWidth);
}
if (_windowChangeCallback) {
_windowChangeCallback(_monIndex, _index, _windowDims);
}
if (_FovLocked) {
updatePlanarLockedFov();
}
}
void WindowControl::onOffsetXChanged(const QString& newText) {
float prevWidth = _windowDims.width();
try {
_windowDims.setX(newText.toInt());
_windowDims.setWidth(prevWidth);
if (_windowChangeCallback) {
_windowChangeCallback(_monIndex, _index, _windowDims);
}
}
catch (std::exception const&) {
//The QIntValidator ensures that the range is a +/- integer
//However, it's possible to enter only a - character which
//causes an exception throw, which is ignored here (when user
//enters an integer after the - then the value will be updated).
}
}
void WindowControl::onOffsetYChanged(const QString& newText) {
float prevHeight = _windowDims.height();
try {
_windowDims.setY(newText.toInt());
_windowDims.setHeight(prevHeight);
if (_windowChangeCallback) {
_windowChangeCallback(_monIndex, _index, _windowDims);
}
}
catch (std::exception const&) {
//See comment in onOffsetXChanged
}
}
void WindowControl::onFullscreenClicked() {
_offsetX->setText("0");
_offsetY->setText("0");
_sizeX->setText(QString::number(_monitorResolutions[_monIndex].width()));
_sizeY->setText(QString::number(_monitorResolutions[_monIndex].height()));
_checkBoxWindowDecor->setCheckState(Qt::Unchecked);
}
void WindowControl::onWebGuiSelection(int selectionState) {
if (_windowGuiCheckCallback && (selectionState == Qt::Checked)) {
_windowGuiCheckCallback(_index);
}
}
void WindowControl::onSpoutSelection(int selectionState) {
if (selectionState == Qt::Checked) {
WindowControl::ProjectionIndeces currentProjectionSelection;
currentProjectionSelection = static_cast<WindowControl::ProjectionIndeces>(
_comboProjection->currentIndex()
);
if ((currentProjectionSelection != ProjectionIndeces::Equirectangular) &&
(currentProjectionSelection != ProjectionIndeces::Fisheye))
{
_comboProjection->setCurrentIndex(
static_cast<int>(ProjectionIndeces::Equirectangular)
);
}
}
}
void WindowControl::onMonitorChanged(int newSelection) {
_monIndex = newSelection;
if (_windowChangeCallback) {
_windowChangeCallback(_monIndex, _index, _windowDims);
}
}
void WindowControl::onProjectionChanged(int newSelection) {
WindowControl::ProjectionIndeces selected
= static_cast<WindowControl::ProjectionIndeces>(newSelection);
_comboQuality->setVisible(selected != ProjectionIndeces::Planar);
_labelQuality->setVisible(selected != ProjectionIndeces::Planar);
_labelFovH->setVisible(selected == ProjectionIndeces::Planar);
_lineFovH->setVisible(selected == ProjectionIndeces::Planar);
_labelFovV->setVisible(selected == ProjectionIndeces::Planar);
_lineFovV->setVisible(selected == ProjectionIndeces::Planar);
_buttonLockFov->setVisible(selected == ProjectionIndeces::Planar);
_labelHeightOffset->setVisible(selected == ProjectionIndeces::Cylindrical);
_lineHeightOffset->setVisible(selected == ProjectionIndeces::Cylindrical);
_checkBoxSpoutOutput->setVisible(selected == ProjectionIndeces::Fisheye
|| selected == ProjectionIndeces::Equirectangular);
}
void WindowControl::onAspectRatioLockClicked() {
_aspectRatioLocked = !_aspectRatioLocked;
_buttonLockAspectRatio->setIcon(_aspectRatioLocked ? _lockIcon : _unlockIcon);
if (_aspectRatioLocked) {
_aspectRatioSize = _windowDims.width() / _windowDims.height();
}
}
void WindowControl::onFovLockClicked() {
_FovLocked = !_FovLocked;
_buttonLockFov->setIcon(_FovLocked ? _lockIcon : _unlockIcon);
if (_FovLocked) {
_lineFovH->setEnabled(false);
_lineFovV->setEnabled(false);
updatePlanarLockedFov();
}
else {
_lineFovH->setEnabled(true);
_lineFovV->setEnabled(true);
}
}
void WindowControl::updatePlanarLockedFov() {
float currentAspectRatio = _windowDims.width() / _windowDims.height();
float relativeRatio = currentAspectRatio / _idealAspectRatio;
if (relativeRatio >= 1.0) {
_lineFovH->setText(QString::number(std::min(_defaultFovH *relativeRatio, 180.f)));
_lineFovV->setText(QString::number(_defaultFovV));
}
else {
_lineFovH->setText(QString::number(_defaultFovH));
_lineFovV->setText(QString::number(std::min(_defaultFovV /relativeRatio, 180.f)));
}
}
void WindowControl::setWindowChangeCallback(
std::function<void(int, int, const QRectF&)> cb)
{
_windowChangeCallback = std::move(cb);
}
void WindowControl::setWebGuiChangeCallback(std::function<void(unsigned int)> cb)
{
_windowGuiCheckCallback = std::move(cb);
}
void WindowControl::uncheckWebGuiOption() {
_checkBoxWebGui->setCheckState(Qt::Unchecked);
}
QRectF& WindowControl::dimensions() {
return _windowDims;
}
std::string WindowControl::windowName() const {
return _windowName->text().toStdString();
}
sgct::ivec2 WindowControl::windowSize() const {
return {
_sizeX->text().toInt(),
_sizeY->text().toInt()
};
}
sgct::ivec2 WindowControl::windowPos() const {
return {
_offsetX->text().toInt(),
_offsetY->text().toInt()
};
}
bool WindowControl::isDecorated() const {
return (_checkBoxWindowDecor->checkState() == Qt::Checked);
}
bool WindowControl::isGuiWindow() const {
return (_checkBoxWebGui->checkState() == Qt::Checked);
}
bool WindowControl::isSpoutSelected() const {
return (_checkBoxSpoutOutput->checkState() == Qt::Checked);
}
WindowControl::ProjectionIndeces WindowControl::projectionSelectedIndex() const {
return
static_cast<WindowControl::ProjectionIndeces>(_comboProjection->currentIndex());
}
int WindowControl::qualitySelectedValue() const {
return QualityValues[_comboQuality->currentIndex()];
}
float WindowControl::fovH() const {
return _lineFovH->text().toFloat();
}
float WindowControl::fovV() const {
return _lineFovV->text().toFloat();
}
float WindowControl::heightOffset() const {
return _lineHeightOffset->text().toFloat();
}
unsigned int WindowControl::monitorNum() const {
return _monIndex;
}

View File

@@ -1044,9 +1044,10 @@ int main(int argc, char* argv[]) {
// to make it possible to find other files in the same directory.
FileSys.registerPathToken(
"${BIN}",
std::filesystem::path(argv[0]).parent_path(),
std::filesystem::current_path() / std::filesystem::path(argv[0]).parent_path(),
ghoul::filesystem::FileSystem::Override::Yes
);
LDEBUG(fmt::format("Registering ${{BIN}} to {}", absPath("${BIN}")));
//
// Parse commandline arguments

View File

@@ -0,0 +1,61 @@
local toggle_sun = {
Identifier = "os.toggle_sun",
Name = "Toggle Sun",
Command = [[
if not is_declared("args") then
openspace.printError("Cannot execute 'os.toggle_sun' manually")
return
end
if args.Transition == "Approaching" then
openspace.setPropertyValueSingle("Scene.SunGlare.Renderable.Enabled", false)
openspace.setPropertyValueSingle("Scene.Sun.Renderable.Enabled", true)
else -- "Exiting"
openspace.setPropertyValueSingle("Scene.SunGlare.Renderable.Enabled", true)
openspace.setPropertyValueSingle("Scene.Sun.Renderable.Enabled", false)
end
]],
Documentation = [[Toggles the visibility of the Sun glare and the Sun globe when the
camera is approaching either so that from far away the Sun Glare is rendered and when
close up, the globe is rendered instead.]],
GuiPath = "/Sun",
IsLocal = false
}
asset.onInitialize(function()
openspace.action.registerAction(toggle_sun)
openspace.event.registerEventAction(
"CameraFocusTransition",
toggle_sun.Identifier,
{ Node = "Sun", Transition = "Approaching" }
)
openspace.event.registerEventAction(
"CameraFocusTransition",
toggle_sun.Identifier,
{ Node = "Sun", Transition = "Exiting" }
)
end)
asset.onDeinitialize(function()
openspace.event.unregisterEventAction(
"CameraFocusTransition",
toggle_sun.Identifier,
{ Node = "Sun", Transition = "Exiting" }
)
openspace.event.unregisterEventAction(
"CameraFocusTransition",
toggle_sun.Identifier,
{ Node = "Sun", Transition = "Approaching" }
)
openspace.action.removeAction(toggle_sun)
end)
asset.meta = {
Name = "Actions - Toggle current Trails",
Version = "1.0",
Description = [[ Asset providing actions to toggle trails]],
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license"
}

View File

@@ -5,12 +5,12 @@ asset.onInitialize(function()
"CameraFocusTransition",
action.show_trail,
{ Transition = "Exiting" }
);
)
openspace.event.registerEventAction(
"CameraFocusTransition",
action.hide_trail,
{ Transition = "Approaching" }
);
)
end)
asset.onDeinitialize(function()
@@ -18,10 +18,10 @@ asset.onDeinitialize(function()
"CameraFocusTransition",
action.show_trail,
{ Transition = "Exiting" }
);
)
openspace.event.unregisterEventAction(
"CameraFocusTransition",
action.hide_trail,
{ Transition = "Approaching" }
);
)
end)

View File

@@ -1,3 +1,9 @@
local fullOS = openspace.systemCapabilities.fullOperatingSystem()
if string.find(fullOS, "Darwin") then
openspace.printWarning("Gaia module (RenderableGaiaStars) not supported on mac")
return
end
-- Download a preprocessed binary octree of Radial Velocity subset values per star (preprocessed into 8 binary files).
local starsFolder = asset.syncedResource({
Name = "Gaia Stars RV",

View File

@@ -27,7 +27,7 @@ local images = asset.syncedResource({
Name = "Pluto Images",
Type = "HttpSynchronization",
Identifier = "newhorizons_plutoencounter_pluto_images",
Version = 1
Version = 2
})
local plutoRadius = 1.173E6

View File

@@ -7,9 +7,7 @@ asset.require("./jupiter/europa/default_layers")
asset.require("./jupiter/ganymede/default_layers")
asset.require("./jupiter/io/default_layers")
asset.require("./mars/default_layers")
asset.require("./mars/moons/layers/colorlayers/deimos_viking")
asset.require("./mars/moons/layers/colorlayers/phobos_viking")
asset.require('./mars/default_layers')
asset.require("./mercury/default_layers")

View File

@@ -0,0 +1,23 @@
local shared = asset.require("util/tle_helper")
local group = {
Title = "Starlink",
Url = "http://www.celestrak.com/NORAD/elements/starlink.txt",
TrailColor = { 0.65, 0.55, 0.55 },
Description = [[LEO satellite constellation launched by SpaceX to provide
broadband internet access.]]
}
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
shared.registerSatelliteGroupObjects(asset, group, tle, true)
asset.meta = {
Name = "Satellites Communications - Starlink",
Version = "1.0",
Description = [[ Satellites asset for Communications - Starlink. Data from
Celestrak]],
Author = "OpenSpace Team",
URL = "https://celestrak.com/NORAD/elements/",
License = "Celestrak"
}

View File

@@ -0,0 +1,21 @@
local shared = asset.require("util/tle_helper")
local group = {
Title = "Active",
Url = "http://www.celestrak.com/NORAD/elements/active.txt",
TrailColor = { 0.45, 0.25, 0.45 },
Description = [[Satellites that employ active communication.]]
}
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
shared.registerSatelliteGroupObjects(asset, group, tle, true)
asset.meta = {
Name = "Satellites Active",
Version = "1.0",
Description = [[ Satellites that employ active communication. Data from Celestrak]],
Author = "OpenSpace Team",
URL = "https://celestrak.com/NORAD/elements/",
License = "Celestrak"
}

View File

@@ -11,6 +11,7 @@ asset.require("./communications/other_comm")
asset.require("./communications/gorizont")
asset.require("./communications/raduga")
asset.require("./communications/molniya")
asset.require("./communications/starlink")
asset.meta = {

View File

@@ -2,6 +2,7 @@ asset.require("./misc/military")
asset.require("./misc/radar")
asset.require("./misc/cubesats")
asset.require("./misc/other")
asset.require("./misc/active")
asset.meta = {

View File

@@ -3,7 +3,7 @@ local globeIdentifier = asset.require("../../mars").Mars.Identifier
local layer = {
Identifier = "Themis_IR_Night_Sweden",
Name = "Themis IR Night [Sweden]",
FilePath = asset.localResource("themis_ir_night_sweden.wms"),
FilePath = asset.localResource("themis_ir_night_sweden.vrt"),
BlendMode = "Color",
Description = [[This mosaic represents the Thermal Emission Imaging System (THEMIS)
-nighttime infrared (IR) 100 meter/pixel mosaic (version 12) released in the

View File

@@ -0,0 +1,26 @@
<VRTDataset rasterXSize="213388" rasterYSize="106695">
<SRS>GEOGCS["GCS_Mars_2000_Sphere",DATUM["D_Mars_2000_Sphere",SPHEROID["Mars_2000_Sphere_IAU_IAG",3396190.0,0.0]],PRIMEM["Reference_Meridian",0.0],UNIT["Degree",0.0174532925199433]]</SRS>
<GeoTransform> -1.8000000000000000e+02, 1.6870676889047182e-03, 0.0000000000000000e+00, 9.0000000000000000e+01, 0.0000000000000000e+00, -1.6870518768452129e-03</GeoTransform>
<VRTRasterBand dataType="Byte" band="1">
<ColorInterp>Gray</ColorInterp>
<SimpleSource>
<SourceFilename relativeToVRT="1">themis_ir_night_sweden.wms</SourceFilename>
<SourceBand>1</SourceBand>
<SourceProperties RasterXSize="213388" RasterYSize="71130" DataType="Byte" BlockXSize="256" BlockYSize="256" />
<SrcRect xOff="0" yOff="0" xSize="213388" ySize="71130" />
<DstRect xOff="0" yOff="17782.5" xSize="213388" ySize="71130" />
</SimpleSource>
</VRTRasterBand>
<VRTRasterBand dataType="Byte" band="2">
<ColorInterp>Alpha</ColorInterp>
<ComplexSource>
<SourceFilename relativeToVRT="1">themis_ir_night_sweden.wms</SourceFilename>
<SourceBand>1</SourceBand>
<SourceProperties RasterXSize="213388" RasterYSize="71130" DataType="Byte" BlockXSize="256" BlockYSize="256" />
<SrcRect xOff="0" yOff="0" xSize="213388" ySize="71130" />
<DstRect xOff="0" yOff="17782.5" xSize="213388" ySize="71130" />
<ScaleRatio>255</ScaleRatio>
<NODATA>0</NODATA>
</ComplexSource>
</VRTRasterBand>
</VRTDataset>

View File

@@ -4,9 +4,9 @@
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>
<UpperLeftY>90.0</UpperLeftY>
<UpperLeftY>60.0</UpperLeftY>
<LowerRightX>180.0</LowerRightX>
<LowerRightY>-90.0</LowerRightY>
<LowerRightY>-60.0</LowerRightY>
<SizeX>213388</SizeX>
<SizeY>71130</SizeY>
<TileLevel>9</TileLevel>

View File

@@ -3,7 +3,7 @@ local globeIdentifier = asset.require("../../mars").Mars.Identifier
local layer = {
Identifier = "Themis_IR_Night_Utah",
Name = "Themis IR Night [Utah]",
FilePath = asset.localResource("themis_ir_night_utah.wms"),
FilePath = asset.localResource("themis_ir_night_utah.vrt"),
BlendMode = "Color",
Description = [[This mosaic represents the Thermal Emission Imaging System (THEMIS)
-nighttime infrared (IR) 100 meter/pixel mosaic (version 12) released in the

View File

@@ -0,0 +1,26 @@
<VRTDataset rasterXSize="213388" rasterYSize="106695">
<SRS>GEOGCS["GCS_Mars_2000_Sphere",DATUM["D_Mars_2000_Sphere",SPHEROID["Mars_2000_Sphere_IAU_IAG",3396190.0,0.0]],PRIMEM["Reference_Meridian",0.0],UNIT["Degree",0.0174532925199433]]</SRS>
<GeoTransform> -1.8000000000000000e+02, 1.6870676889047182e-03, 0.0000000000000000e+00, 9.0000000000000000e+01, 0.0000000000000000e+00, -1.6870518768452129e-03</GeoTransform>
<VRTRasterBand dataType="Byte" band="1">
<ColorInterp>Gray</ColorInterp>
<SimpleSource>
<SourceFilename relativeToVRT="1">themis_ir_night_utah.wms</SourceFilename>
<SourceBand>1</SourceBand>
<SourceProperties RasterXSize="213388" RasterYSize="71130" DataType="Byte" BlockXSize="256" BlockYSize="256" />
<SrcRect xOff="0" yOff="0" xSize="213388" ySize="71130" />
<DstRect xOff="0" yOff="17782.5" xSize="213388" ySize="71130" />
</SimpleSource>
</VRTRasterBand>
<VRTRasterBand dataType="Byte" band="2">
<ColorInterp>Alpha</ColorInterp>
<ComplexSource>
<SourceFilename relativeToVRT="1">themis_ir_night_utah.wms</SourceFilename>
<SourceBand>1</SourceBand>
<SourceProperties RasterXSize="213388" RasterYSize="71130" DataType="Byte" BlockXSize="256" BlockYSize="256" />
<SrcRect xOff="0" yOff="0" xSize="213388" ySize="71130" />
<DstRect xOff="0" yOff="17782.5" xSize="213388" ySize="71130" />
<ScaleRatio>255</ScaleRatio>
<NODATA>0</NODATA>
</ComplexSource>
</VRTRasterBand>
</VRTDataset>

View File

@@ -4,9 +4,9 @@
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>
<UpperLeftY>90.0</UpperLeftY>
<UpperLeftY>60.0</UpperLeftY>
<LowerRightX>180.0</LowerRightX>
<LowerRightY>-90.0</LowerRightY>
<LowerRightY>-60.0</LowerRightY>
<SizeX>213388</SizeX>
<SizeY>71130</SizeY>
<TileLevel>9</TileLevel>

View File

@@ -1,4 +1,13 @@
local transforms = asset.require("../transforms")
local transforms = asset.require('scene/solarsystem/planets/mars/transforms')
local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
local sun = asset.require("scene/solarsystem/sun/sun")
local model = asset.syncedResource({
Name = "Deimos Model",
Type = "HttpSynchronization",
Identifier = "deimos_model",
Version = 1
})
local kernels = asset.syncedResource({
Name = "Mars Spice Kernels",
@@ -25,10 +34,17 @@ local Deimos = {
}
},
Renderable = {
Type = "RenderableGlobe",
Radii = { 15000, 12200, 11000 },
SegmentsPerPatch = 90,
Layers = {}
Type = "RenderableModel",
GeometryFile = model .. "/Deimos_1_1000.glb",
ModelScale = 'Kilometer',
RotationVector = { 180, 0, 180 },
AmbientIntensity = 0.02,
SpecularIntensity = 0.0,
LightSources = {
sun.LightSource
},
PerformShading = true,
DisableFaceCulling = true
},
Tag = { "moon_solarSystem", "moon_terrestrial", "moon_mars" },
GUI = {
@@ -74,11 +90,10 @@ asset.export(Deimos)
asset.export(DeimosTrail)
asset.meta = {
Name = "Deimos",
Version = "1.1",
Description = [[ RenderableGlobe and Trail for Deimos.]],
Version = "1.0",
Description = [[ RenderableModel and Trail for Deimos.]],
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license"

View File

@@ -0,0 +1,63 @@
local transforms = asset.require('../transforms')
local kernels = asset.syncedResource({
Name = "Mars Spice Kernels",
Type = "HttpSynchronization",
Identifier = "mars_kernels",
Version = 1
})
local DeimosGlobe = {
Identifier = "Deimos_Globe",
Parent = transforms.MarsBarycenter.Identifier,
Transform = {
Rotation = {
Type = "SpiceRotation",
SourceFrame = "IAU_DEIMOS",
DestinationFrame = "GALACTIC",
Kernels = kernels .. "mar097.bsp"
},
Translation = {
Type = "SpiceTranslation",
Target = "DEIMOS",
Observer = "MARS BARYCENTER",
Kernels = kernels .. "mar097.bsp"
}
},
Renderable = {
Type = "RenderableGlobe",
Radii = { 7500, 6100, 5200 },
--Radius source
--https://sci.esa.int/documents/35171/36506/1567259108230-5-ESLAB46-Day2-Rosenblatt.pdf
SegmentsPerPatch = 90,
Layers = {}
},
Tag = { "moon_solarSystem", "moon_terrestrial", "moon_mars" },
GUI = {
Name = "Deimos_Globe",
Path = "/Solar System/Planets/Mars",
Description = [[One of two moons of Mars.]]
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(DeimosGlobe)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(DeimosGlobe)
end)
asset.export(DeimosGlobe)
asset.meta = {
Name = "Deimos Globe",
Version = "1.0",
Description = [[ RenderableGlobe for Deimos.]],
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license",
Identifiers = {"Deimos"}
}

View File

@@ -1,4 +1,4 @@
local globeIdentifier = asset.require("../../deimos").Deimos.Identifier
local globeIdentifier = asset.require("./../../deimos_globe").Deimos_Globe.Identifier
local layer = {
Identifier = "Deimos_Global_Mosaic_USGS",

View File

@@ -1,4 +1,4 @@
local globeIdentifier = asset.require("../../phobos").Phobos.Identifier
local globeIdentifier = asset.require("./../../phobos_globe").Phobos_Globe.Identifier
local layer = {
Identifier = "Phobos_Global_Shaded_Relief_USGS",

View File

@@ -1,4 +1,13 @@
local transforms = asset.require("../transforms")
local transforms = asset.require('scene/solarsystem/planets/mars/transforms')
local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
local sun = asset.require("scene/solarsystem/sun/sun")
local model = asset.syncedResource({
Name = "Phobos Model",
Type = "HttpSynchronization",
Identifier = "phobos_model",
Version = 1
})
local kernels = asset.syncedResource({
Name = "Mars Spice Kernels",
@@ -7,6 +16,7 @@ local kernels = asset.syncedResource({
Version = 1
})
local Phobos = {
Identifier = "Phobos",
Parent = transforms.MarsBarycenter.Identifier,
@@ -25,10 +35,17 @@ local Phobos = {
}
},
Renderable = {
Type = "RenderableGlobe",
Radii = { 27000, 22000, 18000 },
SegmentsPerPatch = 90,
Layers = {}
Type = "RenderableModel",
GeometryFile = model .. "/Phobos_1_1000.glb",
ModelScale = 'Kilometer',
RotationVector = { 90, 0, 90 },
AmbientIntensity = 0.02,
SpecularIntensity = 0.0,
LightSources = {
sun.LightSource
},
PerformShading = true,
DisableFaceCulling = true
},
Tag = { "moon_solarSystem", "moon_terrestrial", "moon_mars" },
GUI = {
@@ -46,7 +63,8 @@ local PhobosTrail = {
Translation = {
Type = "SpiceTranslation",
Target = "PHOBOS",
Observer = "MARS BARYCENTER"
Observer = "MARS BARYCENTER",
Kernels = kernels .. "mar097.bsp"
},
Color = { 1.0, 0.605, 0.420 },
Period = 0.31891023,
@@ -77,8 +95,8 @@ asset.export(PhobosTrail)
asset.meta = {
Name = "Phobos",
Version = "1.1",
Description = [[ RenderableGlobe and Trail for Phobos.]],
Version = "1.0",
Description = [[ RenderableModel and Trail for Phobos.]],
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license"

View File

@@ -0,0 +1,63 @@
local transforms = asset.require('../transforms')
local kernels = asset.syncedResource({
Name = "Mars Spice Kernels",
Type = "HttpSynchronization",
Identifier = "mars_kernels",
Version = 1
})
local PhobosGlobe = {
Identifier = "Phobos_Globe",
Parent = transforms.MarsBarycenter.Identifier,
Transform = {
Rotation = {
Type = "SpiceRotation",
SourceFrame = "IAU_PHOBOS",
DestinationFrame = "GALACTIC",
Kernels = kernels .. "mar097.bsp"
},
Translation = {
Type = "SpiceTranslation",
Target = "PHOBOS",
Observer = "MARS BARYCENTER",
Kernels = kernels .. "mar097.bsp"
}
},
Renderable = {
Type = "RenderableGlobe",
Radii = { 13030, 11400, 9140 },
--Radius source
--https://naif.jpl.nasa.gov/pub/naif/generic_kernels/dsk/satellites/willner_etal_phobos.pdf
SegmentsPerPatch = 90,
Layers = {}
},
Tag = { "moon_solarSystem", "moon_terrestrial", "moon_mars" },
GUI = {
Name = "Phobos_Globe",
Path = "/Solar System/Planets/Mars",
Description = [[One of two moons of Mars.]]
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(PhobosGlobe)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(PhobosGlobe)
end)
asset.export(PhobosGlobe)
asset.meta = {
Name = "Phobos Globe",
Version = "1.0",
Description = [[ RenderableGlobe for Phobos.]],
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license",
Identifiers = {"Phobos"}
}

View File

@@ -33,13 +33,15 @@ asset.require("./layers/colorlayers/fesimap_02122015")
asset.require("./layers/colorlayers/mgsimap_02122015")
asset.require("./layers/colorlayers/ssimap_02122015")
asset.require("./layers/heightlayers/messenger_dem_utah")
local heightLayer = asset.require("./layers/heightlayers/messenger_dem_utah")
-- Set enabled layers (temporary solution)
-- @TODO: do this using a boolean that's passed to the 'asset.require' instead
asset.onInitialize(function ()
openspace.setPropertyValueSingle("Scene.Mercury.Renderable.Layers.ColorLayers." ..
colorLayer.layer.Identifier .. ".Enabled", true)
openspace.setPropertyValueSingle("Scene.Mercury.Renderable.Layers.HeightLayers." ..
heightLayer.layer.Identifier .. ".Enabled", true)
end)

View File

@@ -4,6 +4,10 @@ local layer = {
Identifier = "Messenger_DEM_Utah",
Name = "Messenger DEM [Utah]",
FilePath = asset.localResource("messenger_dem_utah.wms"),
Settings = {
Gamma = 1.59,
Multiplier = 1.38
},
TilePixelSize = 64
}

View File

@@ -27,7 +27,7 @@ local Mimas = {
},
Renderable = {
Type = "RenderableGlobe",
Radii = 198000,
Radii = { 207000, 197000, 191000 },
SegmentsPerPatch = 64,
Layers = { },
Labels = {

View File

@@ -12,6 +12,7 @@ local Sun = {
Layers = {},
PerformShading = false
},
ApproachFactor = 15.0,
GUI = {
Name = "Sun",
Path = "/Solar System/Sun",

View File

@@ -27,6 +27,7 @@
],
"assets": [
"base",
"events/toggle_sun",
"scene/solarsystem/planets/earth/earth",
"scene/solarsystem/planets/earth/satellites/satellites"
],
@@ -104,4 +105,4 @@
"major": 1,
"minor": 1
}
}
}

View File

@@ -35,6 +35,7 @@
],
"assets": [
"base",
"events/toggle_sun",
"scene/solarsystem/planets/earth/earth",
"scene/solarsystem/planets/earth/satellites/satellites",
"scene/solarsystem/planets/jupiter/major_moons",
@@ -130,4 +131,4 @@
"major": 1,
"minor": 1
}
}
}

View File

@@ -39,10 +39,10 @@ namespace openspace::interaction {
class Path {
public:
enum Type {
AvoidCollision,
Linear,
enum class Type {
AvoidCollision = 0,
ZoomOutOverview,
Linear,
AvoidCollisionWithLookAt // @TODO (2021-08-13, emmbr) This type right now leads
// to rapid rotations, but is useful in specific
// scenarios, e.g. close to surfaces. Later we want to

View File

@@ -235,6 +235,8 @@ void RenderableBoxGrid::update(const UpdateData&) {
_varray.push_back({ v7.x, v7.y, v7.z });
_varray.push_back({ v3.x, v3.y, v3.z });
setBoundingSphere(glm::length(glm::dvec3(urb)));
glBindVertexArray(_vaoID);
glBindBuffer(GL_ARRAY_BUFFER, _vBufferID);
glBufferData(

View File

@@ -243,6 +243,8 @@ void RenderableGrid::update(const UpdateData&) {
_varray[nr++] = { halfSize.x, y1, 0.f };
}
setBoundingSphere(glm::length(glm::dvec2(halfSize)));
glBindVertexArray(_vaoID);
glBindBuffer(GL_ARRAY_BUFFER, _vBufferID);
glBufferData(

View File

@@ -274,6 +274,8 @@ void RenderableRadialGrid::update(const UpdateData&) {
}
_lines.update();
setBoundingSphere(static_cast<double>(outerRadius));
_gridIsDirty = false;
}

View File

@@ -103,6 +103,9 @@ RenderableSphericalGrid::RenderableSphericalGrid(const ghoul::Dictionary& dictio
_lineWidth = p.lineWidth.value_or(_lineWidth);
addProperty(_lineWidth);
// Radius is always 1
setBoundingSphere(1.0);
}
bool RenderableSphericalGrid::isReady() const {

View File

@@ -460,6 +460,9 @@ bool RenderableDUMeshes::readSpeckFile() {
return false;
}
const float scale = static_cast<float>(toMeter(_unit));
double maxRadius = 0.0;
int meshIndex = 0;
// The beginning of the speck file has a header that either contains comments
@@ -540,23 +543,55 @@ bool RenderableDUMeshes::readSpeckFile() {
// We can now read the vertices data:
for (int l = 0; l < mesh.numU * mesh.numV; ++l) {
std::getline(file, line);
if (line.substr(0, 1) != "}") {
std::stringstream lineData(line);
for (int i = 0; i < 7; ++i) {
GLfloat value;
lineData >> value;
bool errorReading = lineData.rdstate() & std::ifstream::failbit;
if (!errorReading) {
mesh.vertices.push_back(value);
}
else {
break;
}
}
}
else {
if (line.substr(0, 1) == "}") {
break;
}
std::stringstream lineData(line);
// Try to read three values for the position
glm::vec3 pos;
bool success = true;
for (int i = 0; i < 3; ++i) {
GLfloat value;
lineData >> value;
bool errorReading = lineData.rdstate() & std::ifstream::failbit;
if (errorReading) {
success = false;
break;
}
GLfloat scaledValue = value * scale;
pos[i] = scaledValue;
mesh.vertices.push_back(scaledValue);
}
if (!success) {
LERROR(fmt::format(
"Failed reading position on line {} of mesh {} in file: '{}'. "
"Stopped reading mesh data", l, meshIndex, _speckFile
));
break;
}
// Check if new max radius
const double r = glm::length(glm::dvec3(pos));
maxRadius = std::max(maxRadius, r);
// OLD CODE:
// (2022-03-23, emmbr) None of our files included texture coordinates,
// and if they would they would still not be used by the shader
//for (int i = 0; i < 7; ++i) {
// GLfloat value;
// lineData >> value;
// bool errorReading = lineData.rdstate() & std::ifstream::failbit;
// if (!errorReading) {
// mesh.vertices.push_back(value);
// }
// else {
// break;
// }
//}
}
std::getline(file, line);
@@ -569,6 +604,8 @@ bool RenderableDUMeshes::readSpeckFile() {
}
}
setBoundingSphere(maxRadius);
return true;
}
@@ -579,12 +616,6 @@ void RenderableDUMeshes::createMeshes() {
LDEBUG("Creating planes");
for (std::pair<const int, RenderingMesh>& p : _renderingMeshesMap) {
float scale = static_cast<float>(toMeter(_unit));
for (GLfloat& v : p.second.vertices) {
v *= scale;
}
for (int i = 0; i < p.second.numU; ++i) {
GLuint vao;
glGenVertexArrays(1, &vao);
@@ -605,29 +636,32 @@ void RenderableDUMeshes::createMeshes() {
);
// in_position
glEnableVertexAttribArray(0);
// U and V may not be given by the user
if (p.second.vertices.size() / (p.second.numU * p.second.numV) > 3) {
glVertexAttribPointer(
0,
3,
GL_FLOAT,
GL_FALSE,
sizeof(GLfloat) * 5,
reinterpret_cast<GLvoid*>(sizeof(GLfloat) * i * p.second.numV)
);
// (2022-03-23, emmbr) This code was actually never used. We only read three
// values per line and di not handle any texture cooridnates, even if there
// would have been some in the file
//// U and V may not be given by the user
//if (p.second.vertices.size() / (p.second.numU * p.second.numV) > 3) {
// glVertexAttribPointer(
// 0,
// 3,
// GL_FLOAT,
// GL_FALSE,
// sizeof(GLfloat) * 5,
// reinterpret_cast<GLvoid*>(sizeof(GLfloat) * i * p.second.numV)
// );
// texture coords
glEnableVertexAttribArray(1);
glVertexAttribPointer(
1,
2,
GL_FLOAT,
GL_FALSE,
sizeof(GLfloat) * 7,
reinterpret_cast<GLvoid*>(sizeof(GLfloat) * 3 * i * p.second.numV)
);
}
else { // no U and V:
// // texture coords
// glEnableVertexAttribArray(1);
// glVertexAttribPointer(
// 1,
// 2,
// GL_FLOAT,
// GL_FALSE,
// sizeof(GLfloat) * 7,
// reinterpret_cast<GLvoid*>(sizeof(GLfloat) * 3 * i * p.second.numV)
// );
//}
//else { // no U and V:
glVertexAttribPointer(
0,
3,
@@ -636,7 +670,7 @@ void RenderableDUMeshes::createMeshes() {
0,
reinterpret_cast<GLvoid*>(sizeof(GLfloat) * 3 * i * p.second.numV)
);
}
//}
}
// Grid: we need columns

View File

@@ -397,12 +397,17 @@ std::vector<double> RenderablePoints::createDataSlice() {
slice.reserve(4 * _dataset.entries.size());
}
double maxRadius = 0.0;
int colorIndex = 0;
for (const speck::Dataset::Entry& e : _dataset.entries) {
glm::dvec3 p = e.position;
double scale = toMeter(_unit);
p *= scale;
const double r = glm::length(p);
maxRadius = std::max(maxRadius, r);
glm::dvec4 position(p, 1.0);
if (_hasColorMapFile) {
@@ -423,6 +428,7 @@ std::vector<double> RenderablePoints::createDataSlice() {
0 :
colorIndex + 1;
}
setBoundingSphere(maxRadius);
return slice;
}

View File

@@ -48,6 +48,7 @@
#include <ghoul/opengl/texture.h>
#include <ghoul/opengl/textureunit.h>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/component_wise.hpp>
#include <filesystem>
#include <fstream>
#include <optional>
@@ -318,6 +319,10 @@ RenderableGalaxy::RenderableGalaxy(const ghoul::Dictionary& dictionary)
_downScaleVolumeRendering.setVisibility(properties::Property::Visibility::Developer);
addProperty(_downScaleVolumeRendering);
addProperty(_numberOfRayCastingSteps);
// Use max component instead of length, to avoid problems with taking square
// of huge value
setBoundingSphere(glm::compMax(0.5f * _volumeSize));
}
void RenderableGalaxy::initialize() {

View File

@@ -716,7 +716,7 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const {
codegen::lua::GetGeoPositionForCamera,
codegen::lua::LoadWMSCapabilities,
codegen::lua::RemoveWMSServer,
codegen::lua::Capabilities
codegen::lua::CapabilitiesWMS
};
res.scripts = {
absPath("${MODULE_GLOBEBROWSING}/scripts/layer_support.lua")

View File

@@ -437,7 +437,7 @@ getLocalPositionFromGeo(std::string globeIdentifier, double latitude, double lon
* can be used in the 'FilePath' argument for a call to the 'addLayer' function to add the
* value to a globe.
*/
[[codegen::luawrap]] std::vector<ghoul::Dictionary> capabilities(std::string name) {
[[codegen::luawrap]] std::vector<ghoul::Dictionary> capabilitiesWMS(std::string name) {
using namespace openspace;
using namespace globebrowsing;

View File

@@ -131,8 +131,9 @@ void DashboardItemInstruments::render(glm::vec2& penPosition) {
double previous = sequencer.prevCaptureTime(currentTime);
double next = sequencer.nextCaptureTime(currentTime);
double remaining = sequencer.nextCaptureTime(currentTime) - currentTime;
const float t = static_cast<float>(1.0 - remaining / (next - previous));
double remaining = next - currentTime;
float t = static_cast<float>(1.0 - remaining / (next - previous));
t = std::clamp(t, 0.f, 1.f);
if (remaining > 0.0) {
RenderFont(

View File

@@ -168,8 +168,6 @@ if (OS_MACOSX)
ADD_LOGICAL_TARGET("cef_sandbox_lib" "${CEF_SANDBOX_LIB_DEBUG}" "${CEF_SANDBOX_LIB_RELEASE}")
foreach(target IN LISTS Targets)
# Helper executable target.
message(STATUS "set tar : ${target}")
add_executable(${target} MACOSX_BUNDLE ${WEBBROWSER_HELPER_SOURCES})
SET_EXECUTABLE_TARGET_PROPERTIES(${target})
# add_cef_logical_target("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}")

View File

@@ -2155,6 +2155,7 @@ std::vector<std::string> SessionRecording::playbackList() const {
}
}
}
std::sort(fileList.begin(), fileList.end());
return fileList;
}

View File

@@ -70,7 +70,9 @@ namespace {
* value of true is given, then playback will continually loop until it is manually
* stopped.
*/
[[codegen::luawrap]] void startPlaybackDefault(std::string file, bool loop = false) {
[[codegen::luawrap("startPlayback")]] void startPlaybackDefault(std::string file,
bool loop = false)
{
using namespace openspace;
if (file.empty()) {

View File

@@ -218,8 +218,10 @@ joystickAxis(std::string joystickName, int axis)
* Finds the input joystick with the given 'name' and sets the deadzone for a particular
* joystick axis, which means that any input less than this value is completely ignored.
*/
[[codegen::luawrap]] void setJoystickAxisDeadZone(std::string joystickName, int axis,
float deadzone)
[[codegen::luawrap("setAxisDeadZone")]] void setJoystickAxisDeadZone(
std::string joystickName,
int axis,
float deadzone)
{
using namespace openspace;
global::navigationHandler->setJoystickAxisDeadzone(joystickName, axis, deadzone);
@@ -228,7 +230,9 @@ joystickAxis(std::string joystickName, int axis)
/**
* Returns the deadzone for the desired axis of the provided joystick.
*/
[[codegen::luawrap]] float joystickAxisDeadzone(std::string joystickName, int axis) {
[[codegen::luawrap("axisDeadzone")]] float joystickAxisDeadzone(std::string joystickName,
int axis)
{
float deadzone = openspace::global::navigationHandler->joystickAxisDeadzone(
joystickName,
axis

View File

@@ -33,6 +33,7 @@
#include <openspace/navigation/pathcurves/avoidcollisioncurve.h>
#include <openspace/navigation/pathcurves/zoomoutoverviewcurve.h>
#include <openspace/navigation/pathnavigator.h>
#include <openspace/rendering/renderable.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/query/query.h>
#include <openspace/util/collisionhelper.h>
@@ -533,6 +534,34 @@ Waypoint computeWaypointFromNodeInfo(const NodeInfo& info, const Waypoint& start
return Waypoint(targetPos, targetRot, info.identifier);
}
void checkVisibilityAndShowMessage(const SceneGraphNode* node) {
auto isEnabled = [](const Renderable* r) {
std::any propertyValueAny = r->property("Enabled")->get();
return std::any_cast<bool>(propertyValueAny);
};
// Show some info related to the visiblity of the object
const Renderable* renderable = node->renderable();
if (!renderable) {
// Check if any of the children are visible, if it has children
bool foundVisible = false;
for (const SceneGraphNode* child : node->children()) {
const Renderable* cr = child->renderable();
if (cr && isEnabled(cr)) {
foundVisible = true;
break;
}
}
if (!foundVisible) {
LINFO("Creating path to a node without a renderable or visible child nodes");
}
}
else if (!isEnabled(renderable)) {
LINFO("Creating path to disabled object");
}
}
Path createPathFromDictionary(const ghoul::Dictionary& dictionary,
std::optional<Path::Type> forceType)
{
@@ -606,6 +635,8 @@ Path createPathFromDictionary(const ghoul::Dictionary& dictionary,
throw PathCurve::TooShortPathError("Path too short!");
}
checkVisibilityAndShowMessage(waypointToAdd.node());
try {
return Path(startPoint, waypointToAdd, type, duration);
}

View File

@@ -123,10 +123,10 @@ PathNavigator::PathNavigator()
, _relevantNodeTags(RelevantNodeTagsInfo)
{
_defaultPathType.addOptions({
{ Path::Type::AvoidCollision, "AvoidCollision" },
{ Path::Type::ZoomOutOverview, "ZoomOutOverview"},
{ Path::Type::Linear, "Linear" },
{ Path::Type::AvoidCollisionWithLookAt, "AvoidCollisionWithLookAt"}
{ static_cast<int>(Path::Type::AvoidCollision), "AvoidCollision" },
{ static_cast<int>(Path::Type::ZoomOutOverview), "ZoomOutOverview" },
{ static_cast<int>(Path::Type::Linear), "Linear" },
{ static_cast<int>(Path::Type::AvoidCollisionWithLookAt), "AvoidCollisionWithLookAt"}
});
addProperty(_defaultPathType);
@@ -343,8 +343,7 @@ void PathNavigator::continuePath() {
}
Path::Type PathNavigator::defaultPathType() const {
const int pathType = _defaultPathType;
return Path::Type(pathType);
return static_cast<Path::Type>(_defaultPathType.value());
}
double PathNavigator::minValidBoundingSphere() const {

View File

@@ -95,7 +95,7 @@ namespace {
}
// Returns the L2 associativity.
[[codegen::luawrap]] int l2Associativity() {
[[codegen::luawrap("L2Associativity")]] int l2Associativity() {
int assoc = static_cast<int>(CpuCap.L2Associativity());
return assoc;
}

View File

@@ -164,6 +164,7 @@ scripting::LuaLibrary Time::luaLibrary() {
codegen::lua::InterpolateTimeRelative,
codegen::lua::CurrentTime,
codegen::lua::CurrentTimeUTC,
codegen::lua::CurrentTimeSpice,
codegen::lua::CurrentWallTime,
codegen::lua::CurrentApplicationTime,
codegen::lua::AdvancedTime

View File

@@ -273,7 +273,16 @@ namespace {
/**
* Returns the current time as an ISO 8601 date string (YYYY-MM-DDTHH:MN:SS).
*/
[[codegen::luawrap]] std::string currentTimeUTC() {
[[codegen::luawrap("UTC")]] std::string currentTimeUTC() {
return std::string(openspace::global::timeManager->time().ISO8601());
}
/**
* Returns the current time as an date string of the form
* (YYYY MON DDTHR:MN:SC.### ::RND) as returned by SPICE.
*/
[[codegen::luawrap("SPICE")]] std::string currentTimeSpice() {
return std::string(openspace::global::timeManager->time().UTC());
}