Merge branch 'master' into thesis/2022/software-integration

This commit is contained in:
Micah Acinapura
2025-02-03 16:39:13 -05:00
2929 changed files with 78299 additions and 49527 deletions

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -78,7 +78,7 @@ public:
void setAtmosphereDimmingFactor(float atmosphereDimmingFactor);
// Relative mutators
void rotate(glm::dquat rotation);
void rotate(const glm::dquat& rotation);
// Accessors
// Remove Vec3 from the name when psc is gone

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -22,21 +22,21 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___SCENELICENSEWRITER___H__
#define __OPENSPACE_CORE___SCENELICENSEWRITER___H__
#ifndef __OPENSPACE_CORE___CSVLOADER___H__
#define __OPENSPACE_CORE___CSVLOADER___H__
#include <openspace/json.h>
#include <vector>
#include <openspace/data/dataloader.h>
#include <filesystem>
#include <optional>
namespace openspace {
namespace openspace::dataloader::csv {
class SceneLicenseWriter {
public:
SceneLicenseWriter();
nlohmann::json generateJsonList() const;
nlohmann::json generateJsonGroupedByLicense() const;
};
Dataset loadCsvFile(std::filesystem::path path,
std::optional<DataMapping> specs = std::nullopt);
} // namespace openspace
std::vector<Dataset::Texture> loadTextureMapFile(std::filesystem::path path,
const std::set<int>& texturesInData);
#endif // __OPENSPACE_CORE___SCENELICENSEWRITER___H__
} // namespace openspace::dataloader
#endif // __OPENSPACE_CORE___CSVLOADER___H__

View File

@@ -0,0 +1,141 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2025 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___DATALOADER___H__
#define __OPENSPACE_CORE___DATALOADER___H__
#include <openspace/data/datamapping.h>
#include <ghoul/glm.h>
#include <ghoul/misc/boolean.h>
#include <ghoul/misc/csvreader.h>
#include <filesystem>
#include <optional>
#include <string>
#include <vector>
namespace openspace::dataloader {
/**
* A dataset representing objects with positions and various other data columns.
* Based on the SPECK format originally used for the digital universe datasets.
* Mostly used for point-data.
*
* The read data files may also have associated texture values to be used for the
* points.
*/
struct Dataset {
struct Variable {
int index = -1;
std::string name;
};
std::vector<Variable> variables;
struct Texture {
int index = -1;
std::string file;
};
std::vector<Texture> textures;
int textureDataIndex = -1;
int orientationDataIndex = -1;
struct Entry {
glm::vec3 position = glm::vec3(0.f);
std::vector<float> data;
std::optional<std::string> comment;
};
std::vector<Entry> entries;
/// This variable can be used to get an understanding of the world scale size of
/// the dataset
float maxPositionComponent = 0.f;
bool isEmpty() const;
int index(std::string_view variableName) const;
bool normalizeVariable(std::string_view variableName);
glm::vec2 findValueRange(int variableIndex) const;
glm::vec2 findValueRange(std::string_view variableName) const;
};
struct Labelset {
int textColorIndex = -1;
struct Entry {
glm::vec3 position = glm::vec3(0.f);
std::string identifier;
std::string text;
bool isEnabled = true;
};
std::vector<Entry> entries;
};
struct ColorMap {
std::optional<glm::vec4> belowRangeColor;
std::optional<glm::vec4> aboveRangeColor;
std::optional<glm::vec4> nanColor;
std::vector<glm::vec4> entries;
};
namespace data {
Dataset loadFile(std::filesystem::path path,
std::optional<DataMapping> specs = std::nullopt);
std::optional<Dataset> loadCachedFile(const std::filesystem::path& path);
void saveCachedFile(const Dataset& dataset, const std::filesystem::path& path);
Dataset loadFileWithCache(std::filesystem::path path,
std::optional<DataMapping> specs = std::nullopt);
} // namespace data
namespace label {
Labelset loadFile(std::filesystem::path path,
std::optional<DataMapping> specs = std::nullopt);
std::optional<Labelset> loadCachedFile(const std::filesystem::path& path);
void saveCachedFile(const Labelset& labelset, const std::filesystem::path& path);
Labelset loadFileWithCache(std::filesystem::path path);
Labelset loadFromDataset(const dataloader::Dataset& dataset);
} // namespace label
namespace color {
ColorMap loadFile(std::filesystem::path path,
std::optional<DataMapping> specs = std::nullopt);
std::optional<ColorMap> loadCachedFile(const std::filesystem::path& path);
void saveCachedFile(const ColorMap& colorMap, const std::filesystem::path& path);
ColorMap loadFileWithCache(std::filesystem::path path);
} // namespace color
} // namespace openspace::dataloader
#endif // __OPENSPACE_CORE___DATALOADER___H__

View File

@@ -0,0 +1,84 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2025 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___DATAMAPPING___H__
#define __OPENSPACE_CORE___DATAMAPPING___H__
#include <optional>
#include <string>
#include <vector>
namespace openspace::documentation { struct Documentation; }
namespace ghoul { class Dictionary; }
namespace openspace::dataloader {
struct DataMapping {
static DataMapping createFromDictionary(const ghoul::Dictionary& dictionary);
static documentation::Documentation Documentation();
bool hasExcludeColumns() const;
bool isExcludeColumn(std::string_view column) const;
bool checkIfAllProvidedColumnsExist(const std::vector<std::string>& columns) const;
std::optional<std::string> xColumnName;
std::optional<std::string> yColumnName;
std::optional<std::string> zColumnName;
std::optional<std::string> nameColumn;
std::optional<std::string> textureColumn;
std::optional<std::filesystem::path> textureMap;
std::optional<float> missingDataValue;
bool isCaseSensitive = false;
std::vector<std::string> excludeColumns;
// OBS! When new parameters are added they should be included in the generateHash
// function
};
/**
* Generate a string based on the data mapping, that can be used to uniquely
* identify the dataset.
*/
std::string generateHashString(const DataMapping& dm);
bool isPositionColumn(const std::string& c, const std::optional<DataMapping>& mapping);
bool isColumnX(const std::string& c, const std::optional<DataMapping>& mapping);
bool isColumnY(const std::string& c, const std::optional<DataMapping>& mapping);
bool isColumnZ(const std::string& c, const std::optional<DataMapping>& mapping);
bool isNameColumn(const std::string& c, const std::optional<DataMapping>& mapping);
bool isTextureColumn(const std::string& c, const std::optional<DataMapping>& mapping);
} // namespace openspace::dataloader
#endif // __OPENSPACE_CORE___DATAMAPPING___H__

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -22,34 +22,22 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___CONVERTRECFILEVERSIONTASK___H__
#define __OPENSPACE_CORE___CONVERTRECFILEVERSIONTASK___H__
#ifndef __OPENSPACE_CORE___SPECKLOADER___H__
#define __OPENSPACE_CORE___SPECKLOADER___H__
#include <openspace/util/task.h>
#include <openspace/interaction/sessionrecording.h>
#include <ghoul/glm.h>
#include <openspace/data/dataloader.h>
#include <filesystem>
#include <string>
#include <optional>
namespace openspace::interaction {
namespace openspace::dataloader::speck {
class ConvertRecFileVersionTask : public Task {
public:
ConvertRecFileVersionTask(const ghoul::Dictionary& dictionary);
~ConvertRecFileVersionTask() override;
std::string description() override;
void perform(const Task::ProgressCallback& progressCallback) override;
static documentation::Documentation documentation();
void convert();
SessionRecording* sessRec;
Dataset loadSpeckFile(std::filesystem::path path,
std::optional<DataMapping> specs = std::nullopt);
private:
std::string _inFilename;
std::filesystem::path _inFilePath;
std::string _valueFunctionLua;
};
Labelset loadLabelFile(std::filesystem::path path);
} // namespace openspace::interaction
ColorMap loadCmapFile(std::filesystem::path path);
#endif // __OPENSPACE_CORE___CONVERTRECFILEVERSIONTASK___H__
} // namespace openspace::dataloader::speck
#endif // __OPENSPACE_CORE___SPECKLOADER___H__

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -36,7 +36,10 @@ namespace ghoul { class Dictionary; }
namespace openspace::documentation {
class Verifier;
BooleanType(Optional);
BooleanType(Private);
/**
* The TestResult structure returns the information from the #testSpecification method. It
@@ -52,20 +55,24 @@ struct TestResult {
* offense.
*/
struct Offense {
/**
* The Reason for the offense
*/
/// The Reason for the offense
enum class Reason {
MissingKey, ///< The offending key that was requested was not found
WrongType, ///< The key's value was not of the expected type
Verification, ///< The value did not pass a necessary non-type verifier
UnknownIdentifier ///< The identifier for a ReferencingVerifier did not exist
/// Unknown reason
Unknown,
/// The offending key that was requested was not found
MissingKey,
/// The key's value was not of the expected type
WrongType,
/// The value did not pass a necessary non-type verifier
Verification,
/// The identifier for a ReferencingVerifier did not exist
UnknownIdentifier
};
/// The offending key that caused the Offense. In the case of a nested table,
/// this value will be the fully qualified name of the key
std::string offender;
/// The Reason that caused this offense
Reason reason;
Reason reason = Reason::Unknown;
/// An optional explanation for when a verification fails
std::string explanation;
};
@@ -77,11 +84,10 @@ struct TestResult {
* might be removed in a latter version.
*/
struct Warning {
/**
* The reason for the warning
*/
/// The reason for the warning
enum class Reason {
Deprecated ///< The value is marked as deprecated and should not used
/// The value is marked as deprecated and should not used
Deprecated
};
/// The offending key that caused the Warning. In the case of a nested table,
@@ -91,7 +97,6 @@ struct TestResult {
Reason reason;
};
/// Is `true` if the TestResult is positive, `false` otherwise
bool success = false;
/// Contains a list of offenses that were found in the test. Is empty if
@@ -123,8 +128,6 @@ struct SpecificationError : public ghoul::RuntimeError {
void logError(const SpecificationError& error, std::string component = "");
struct Verifier;
/**
* A DocumentationEntry provides the specification for a single key, which is tested using
* the provided Verifier. Each DocumentationEntry can contain a textual documentation that
@@ -133,10 +136,10 @@ struct Verifier;
* DocumentationEntry::Wildcard, any key in the containing Documentation will be tested
* against the provided verifier. The most convenient way of creating DocumentationEntry%s
* is by using an inline initializer list such as:
*\verbatim
DocumentationEntry e = { "key", new IntVerifier, "Documentation text", Optional::Yes };
\endverbatim
* ```
* DocumentationEntry e = { "key", new IntVerifier, "Documentation text", Optional::Yes };
* ```
*
* Furthermore, these initializer lists can be crated all at once for a Documentation.
* Even if the Verifier%s are specified using the `new` operators, they will not leak
* memory as the DocumentationEntry takes ownership of them in the constructor.
@@ -159,42 +162,50 @@ struct DocumentationEntry {
* contains this DocumentationEntry will be matched
* \param v The Verifier that is used to test the \p k%'s value to determine if it is
* a valid value
* \param doc The textual documentation that describes the DocumentationEntry in a
* human readable format
* \param opt Determines whether the Documentation containing this DocumentationEntry
* must have a key \p key, or whether it is optional
* \param priv Determines whether the DocumentationEntry is considered private. If it
* is, then shall not be reported in a user-facing manner, but its values
* should still be checked when verifying the correctness and completeness of
* an entry
* \param doc The textual documentation that describes the DocumentationEntry in a
* human readable format
*
* \pre \p k must not be empty
* \pre \p v must not be nullptr
*/
DocumentationEntry(std::string k, std::shared_ptr<Verifier> v,
Optional opt, std::string doc = "");
Optional opt = Optional::No, Private priv = Private::No, std::string doc = "");
/**
* The constructor for a DocumentationEntry describing a key \p k in a Documentation.
* The value for the key (or each value in the case of the
* DocumentationEntry::Wildcard) is tested using the verifier \p v, that specifies the
* conditions that the \p k%'s value has to fulfill. The textual documentation
* \p doc shall describe the usage of the key-value pair and will be printed for human
* consumption for example in the DocumentationEngine. Each DocumentationEntry can
* further be \p opt.
*
* \param k The key for which this DocumentationEntry is valid. If this valid is
* equal to DocumentationEntry::Wildcard, each entry in the Documentation that
* contains this DocumentationEntry will be matched
* \param v The Verifier that is used to test the \p key%'s value to determine if it is
* a valid value. The DocumentationEntry will take ownership of the passed
* object
* \param doc The textual documentation that describes the DocumentationEntry in a
* human readable format
* \param opt Determines whether the Documentation containing this DocumentationEntry
* must have a key \p key, or whether it is optional
*
* \pre \p k must not be empty
* \pre \p v must not be nullptr
*/
DocumentationEntry(std::string k, Verifier* v, Optional opt,
std::string doc = "");
* The constructor for a DocumentationEntry describing a key \p k in a Documentation.
* The value for the key (or each value in the case of the
* DocumentationEntry::Wildcard) is tested using the verifier \p v, that specifies the
* conditions that the \p k%'s value has to fulfill. The textual documentation
* \p doc shall describe the usage of the key-value pair and will be printed for human
* consumption for example in the DocumentationEngine. Each DocumentationEntry can
* further be \p opt.
*
* \param k The key for which this DocumentationEntry is valid. If this valid is
* equal to DocumentationEntry::Wildcard, each entry in the Documentation that
* contains this DocumentationEntry will be matched
* \param v The Verifier that is used to test the \p key%'s value to determine if it
* is a valid value. The DocumentationEntry will take ownership of the passed
* object
* \param opt Determines whether the Documentation containing this DocumentationEntry
* must have a key \p key, or whether it is optional
* \param priv Determines whether the DocumentationEntry is considered private. If it
* is, then shall not be reported in a user-facing manner, but its values
* should still be checked when verifying the correctness and completeness of
* an entry
* \param doc The textual documentation that describes the DocumentationEntry in a
* human readable format
*
* \pre \p k must not be empty
* \pre \p v must not be nullptr
*/
DocumentationEntry(std::string k, Verifier* v, Optional opt = Optional::No,
Private priv = Private::No, std::string doc = "");
/// The key that is described by this DocumentationEntry
std::string key;
@@ -202,11 +213,12 @@ struct DocumentationEntry {
std::shared_ptr<Verifier> verifier;
/// Determines whether the described DocumentationEntry is optional or not
Optional optional;
/// Determines if the entry should be visible to the user
Private isPrivate;
/// The textual description of this DocumentationEntry
std::string documentation;
};
/**
* This struct contains the documentation and specification for a ghoul::Dictionary. It is
* used to impose restrictions on keys and values and determine whether a given
@@ -214,16 +226,16 @@ struct DocumentationEntry {
* #testSpecificationAndThrow methods). Each Documentation consists of a human-readable
* `name`, and a list of DocumentationEntry%s that each describe a single key value. The
* most convenient way of creating a Documentation is by using nested initializer lists:
*\verbatim
Documentation doc = {
"Documentation for an arbitrary dictionary",
{ // A list of DocumentationEntry%s; also specified using initializer lists
{ "key1", new IntVerifier, "Documentation key1", Optional::Yes },
{ "key2", new FloatVerifier, "Documentation key2" },
{ "key3", new StringVerifier }
}
};
\endverbatim
* ```
* Documentation doc = {
* "Documentation for an arbitrary dictionary",
* { // A list of DocumentationEntry%s; also specified using initializer lists
* { "key1", new IntVerifier, "Documentation key1", Optional::Yes },
* { "key2", new FloatVerifier, "Documentation key2" },
* { "key3", new StringVerifier }
* }
* };
* ```
*
* If multiple DocumentationEntries cover the same key, they are all evaluated for that
* specific key. The same holds true if there is a DocumentationEntry with a
@@ -231,43 +243,14 @@ Documentation doc = {
* both the wildcard and the specialized entry will be evaluated.
*/
struct Documentation {
using DocumentationEntries = std::vector<documentation::DocumentationEntry>;
/**
* Creates a Documentation with a human-readable name \p n and a list of entries
* \p ents.
*
* \param n The human-readable name of this Documentation
* \param i A unique identifier which can be used by applications (or other
* Documentation%s to reference this entry
* \param ents A list of DocumentationEntry%s that describe the individual keys for
* this entrie Documentation
*/
Documentation(std::string n, std::string i, DocumentationEntries ents = {});
/**
* Creates a Documentation with a human-readable name \p n.
*
* \param n The human-readable name of this Documentation
* \param ents A list of DocumentationEntry%s that describe the individual keys for
* this entrie Documentation
*/
Documentation(std::string n, DocumentationEntries ents = {});
/**
* Creates a Documentation.
*
* \param entries A list of DocumentationEntry%s that describe the individual keys for
* this entrie Documentation
*/
Documentation(DocumentationEntries ents = {});
/// The human-readable name of the Documentation
std::string name;
/// A unique identifier which can be used to reference this Documentation
std::string id;
/// A general description for the entire documented entity
std::string description;
/// A list of specifications that are describing this Documentation
DocumentationEntries entries;
std::vector<documentation::DocumentationEntry> entries;
};
/**
@@ -286,20 +269,21 @@ TestResult testSpecification(const Documentation& documentation,
const ghoul::Dictionary& dictionary);
/**
* This method tests whether a provided ghoul::Dictionary \p dictionary adheres to the
* specification \p documentation. If the \p dictionary does not adhere to the
* specification a SpecificationError is thrown, and the exception contains the TestResult
* that contains more information about the offending keys. If the \p dictionary adheres to
* the \p documentation, the method returns normally.
*
* \param documentation The Documentation that the \p dictionary is tested against
* \param dictionary The ghoul::Dictionary that is to be tested against the
* \p documentation
* \param component The component that is using this method; this argument is passed to the
* SpecificationError that is thrown in case of not adhering to the \p documentation
*
* \throw SpecificationError If the \p dictionary does not adhere to the \p documentation
*/
* This method tests whether a provided ghoul::Dictionary \p dictionary adheres to the
* specification \p documentation. If the \p dictionary does not adhere to the
* specification a SpecificationError is thrown, and the exception contains the TestResult
* that contains more information about the offending keys. If the \p dictionary adheres
* to the \p documentation, the method returns normally.
*
* \param documentation The Documentation that the \p dictionary is tested against
* \param dictionary The ghoul::Dictionary that is to be tested against the
* \p documentation
* \param component The component that is using this method; this argument is passed to
* the SpecificationError that is thrown in case of not adhering to the
* \p documentation
*
* \throw SpecificationError If the \p dictionary does not adhere to the \p documentation
*/
void testSpecificationAndThrow(const Documentation& documentation,
const ghoul::Dictionary& dictionary, std::string component);

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -27,6 +27,7 @@
#include <openspace/documentation/documentation.h>
#include <openspace/json.h>
#include <openspace/properties/propertyowner.h>
#include <ghoul/misc/exception.h>
namespace openspace::documentation {
@@ -47,8 +48,7 @@ public:
* Constructor of a DuplicateDocumentationException storing the offending
* Documentation for later use.
*
* \param doc The Documentation whose identifier was previously
* registered
* \param doc The Documentation whose identifier was previously registered
*/
DuplicateDocumentationException(Documentation doc);
@@ -87,12 +87,19 @@ public:
*/
static DocumentationEngine& ref();
std::string generateJson() const;
void writeJavascriptDocumentation() const;
void writeJsonDocumentation() const;
nlohmann::json generateJsonJson() const;
nlohmann::json generateScriptEngineJson() const;
nlohmann::json generateFactoryManagerJson() const;
nlohmann::json generateKeybindingsJson() const;
nlohmann::json generatePropertyOwnerJson(properties::PropertyOwner* owner) const;
nlohmann::json generateLicenseGroupsJson() const;
nlohmann::json generateLicenseListJson() const;
nlohmann::json generateActionJson() const;
nlohmann::json generateEventJson() const;
private:
/// The list of all Documentation%s that are stored by the DocumentationEngine
std::vector<Documentation> _documentations;

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -24,390 +24,12 @@
#include <ghoul/misc/dictionary.h>
#include <ghoul/fmt.h>
#include <ghoul/format.h>
#include <ghoul/misc/assert.h>
#include <iterator>
#include <numeric>
#include <sstream>
template <>
struct std::less<glm::vec2> {
bool operator()(const glm::vec2& a, const glm::vec2& b) const {
return a.x < b.x && a.x < b.y;
}
};
template <>
struct std::less<glm::vec3> {
bool operator()(const glm::vec3& a, const glm::vec3& b) const {
return a.x < b.x && a.x < b.y && a.z < b.z;
}
};
template <>
struct std::less<glm::vec4> {
bool operator()(const glm::vec4& a, const glm::vec4& b) const {
return a.x < b.x && a.x < b.y && a.z < b.z && a.w < b.w;
}
};
template <>
struct std::less<glm::ivec2> {
bool operator()(const glm::ivec2& a, const glm::ivec2& b) const {
return a.x < b.x && a.x < b.y;
}
};
template <>
struct std::less<glm::ivec3> {
bool operator()(const glm::ivec3& a, const glm::ivec3& b) const {
return a.x < b.x && a.x < b.y && a.z < b.z;
}
};
template <>
struct std::less<glm::ivec4> {
bool operator()(const glm::ivec4& a, const glm::ivec4& b) const {
return a.x < b.x && a.x < b.y && a.z < b.z && a.w < b.w;
}
};
template <>
struct std::less<glm::dvec2> {
bool operator()(const glm::dvec2& a, const glm::dvec2& b) const {
return a.x < b.x && a.x < b.y;
}
};
template <>
struct std::less<glm::dvec3> {
bool operator()(const glm::dvec3& a, const glm::dvec3& b) const {
return a.x < b.x && a.x < b.y && a.z < b.z;
}
};
template <>
struct std::less<glm::dvec4> {
bool operator()(const glm::dvec4& a, const glm::dvec4& b) const {
return a.x < b.x && a.x < b.y && a.z < b.z && a.w < b.w;
}
};
template <>
struct std::less_equal<glm::vec2> {
bool operator()(const glm::vec2& a, const glm::vec2& b) const {
return a.x <= b.x && a.x <= b.y;
}
};
template <>
struct std::less_equal<glm::vec3> {
bool operator()(const glm::vec3& a, const glm::vec3& b) const {
return a.x <= b.x && a.x <= b.y && a.z <= b.z;
}
};
template <>
struct std::less_equal<glm::vec4> {
bool operator()(const glm::vec4& a, const glm::vec4& b) const {
return a.x <= b.x && a.x <= b.y && a.z <= b.z && a.w <= b.w;
}
};
template <>
struct std::less_equal<glm::ivec2> {
bool operator()(const glm::ivec2& a, const glm::ivec2& b) const {
return a.x <= b.x && a.x <= b.y;
}
};
template <>
struct std::less_equal<glm::ivec3> {
bool operator()(const glm::ivec3& a, const glm::ivec3& b) const {
return a.x <= b.x && a.x <= b.y && a.z <= b.z;
}
};
template <>
struct std::less_equal<glm::ivec4> {
bool operator()(const glm::ivec4& a, const glm::ivec4& b) const {
return a.x <= b.x && a.x <= b.y && a.z <= b.z && a.w <= b.w;
}
};
template <>
struct std::less_equal<glm::dvec2> {
bool operator()(const glm::dvec2& a, const glm::dvec2& b) const {
return a.x <= b.x && a.x <= b.y;
}
};
template <>
struct std::less_equal<glm::dvec3> {
bool operator()(const glm::dvec3& a, const glm::dvec3& b) const {
return a.x <= b.x && a.x <= b.y && a.z <= b.z;
}
};
template <>
struct std::less_equal<glm::dvec4> {
bool operator()(const glm::dvec4& a, const glm::dvec4& b) const {
return a.x <= b.x && a.x <= b.y && a.z <= b.z && a.w <= b.w;
}
};
template <>
struct std::greater<glm::vec2> {
bool operator()(const glm::vec2& a, const glm::vec2& b) const {
return a.x > b.x && a.x > b.y;
}
};
template <>
struct std::greater<glm::vec3> {
bool operator()(const glm::vec3& a, const glm::vec3& b) const {
return a.x > b.x && a.x > b.y && a.z > b.z;
}
};
template <>
struct std::greater<glm::vec4> {
bool operator()(const glm::vec4& a, const glm::vec4& b) const {
return a.x > b.x && a.x > b.y && a.z > b.z && a.w > b.w;
}
};
template <>
struct std::greater<glm::ivec2> {
bool operator()(const glm::ivec2& a, const glm::ivec2& b) const {
return a.x > b.x && a.x > b.y;
}
};
template <>
struct std::greater<glm::ivec3> {
bool operator()(const glm::ivec3& a, const glm::ivec3& b) const {
return a.x > b.x && a.x > b.y && a.z > b.z;
}
};
template <>
struct std::greater<glm::ivec4> {
bool operator()(const glm::ivec4& a, const glm::ivec4& b) const {
return a.x > b.x && a.x > b.y && a.z > b.z && a.w > b.w;
}
};
template <>
struct std::greater<glm::dvec2> {
bool operator()(const glm::dvec2& a, const glm::dvec2& b) const {
return a.x > b.x && a.x > b.y;
}
};
template <>
struct std::greater<glm::dvec3> {
bool operator()(const glm::dvec3& a, const glm::dvec3& b) const {
return a.x > b.x && a.x > b.y && a.z > b.z;
}
};
template <>
struct std::greater<glm::dvec4> {
bool operator()(const glm::dvec4& a, const glm::dvec4& b) const {
return a.x > b.x && a.x > b.y && a.z > b.z && a.w > b.w;
}
};
template <>
struct std::greater_equal<glm::vec2> {
bool operator()(const glm::vec2& a, const glm::vec2& b) const {
return a.x >= b.x && a.x >= b.y;
}
};
template <>
struct std::greater_equal<glm::vec3> {
bool operator()(const glm::vec3& a, const glm::vec3& b) const {
return a.x >= b.x && a.x >= b.y && a.z >= b.z;
}
};
template <>
struct std::greater_equal<glm::vec4> {
bool operator()(const glm::vec4& a, const glm::vec4& b) const {
return a.x >= b.x && a.x >= b.y && a.z >= b.z && a.w >= b.w;
}
};
template <>
struct std::greater_equal<glm::ivec2> {
bool operator()(const glm::ivec2& a, const glm::ivec2& b) const {
return a.x >= b.x && a.x >= b.y;
}
};
template <>
struct std::greater_equal<glm::ivec3> {
bool operator()(const glm::ivec3& a, const glm::ivec3& b) const {
return a.x >= b.x && a.x >= b.y && a.z >= b.z;
}
};
template <>
struct std::greater_equal<glm::ivec4> {
bool operator()(const glm::ivec4& a, const glm::ivec4& b) const {
return a.x >= b.x && a.x >= b.y && a.z >= b.z && a.w >= b.w;
}
};
template <>
struct std::greater_equal<glm::dvec2> {
bool operator()(const glm::dvec2& a, const glm::dvec2& b) const {
return a.x >= b.x && a.x >= b.y;
}
};
template <>
struct std::greater_equal<glm::dvec3> {
bool operator()(const glm::dvec3& a, const glm::dvec3& b) const {
return a.x >= b.x && a.x >= b.y && a.z >= b.z;
}
};
template <>
struct std::greater_equal<glm::dvec4> {
bool operator()(const glm::dvec4& a, const glm::dvec4& b) const {
return a.x >= b.x && a.x >= b.y && a.z >= b.z && a.w >= b.w;
}
};
template <>
struct std::equal_to<glm::vec2> {
bool operator()(const glm::vec2& a, const glm::vec2& b) const {
return a.x == b.x && a.x == b.y;
}
};
template <>
struct std::equal_to<glm::vec3> {
bool operator()(const glm::vec3& a, const glm::vec3& b) const {
return a.x == b.x && a.x == b.y && a.z == b.z;
}
};
template <>
struct std::equal_to<glm::vec4> {
bool operator()(const glm::vec4& a, const glm::vec4& b) const {
return a.x == b.x && a.x == b.y && a.z == b.z && a.w == b.w;
}
};
template <>
struct std::equal_to<glm::ivec2> {
bool operator()(const glm::ivec2& a, const glm::ivec2& b) const {
return a.x == b.x && a.x == b.y;
}
};
template <>
struct std::equal_to<glm::ivec3> {
bool operator()(const glm::ivec3& a, const glm::ivec3& b) const {
return a.x == b.x && a.x == b.y && a.z == b.z;
}
};
template <>
struct std::equal_to<glm::ivec4> {
bool operator()(const glm::ivec4& a, const glm::ivec4& b) const {
return a.x == b.x && a.x == b.y && a.z == b.z && a.w == b.w;
}
};
template <>
struct std::equal_to<glm::dvec2> {
bool operator()(const glm::dvec2& a, const glm::dvec2& b) const {
return a.x == b.x && a.x == b.y;
}
};
template <>
struct std::equal_to<glm::dvec3> {
bool operator()(const glm::dvec3& a, const glm::dvec3& b) const {
return a.x == b.x && a.x == b.y && a.z == b.z;
}
};
template <>
struct std::equal_to<glm::dvec4> {
bool operator()(const glm::dvec4& a, const glm::dvec4& b) const {
return a.x == b.x && a.x == b.y && a.z == b.z && a.w == b.w;
}
};
template <>
struct std::not_equal_to<glm::vec2> {
bool operator()(const glm::vec2& a, const glm::vec2& b) const {
return a.x != b.x && a.x != b.y;
}
};
template <>
struct std::not_equal_to<glm::vec3> {
bool operator()(const glm::vec3& a, const glm::vec3& b) const {
return a.x != b.x && a.x != b.y && a.z != b.z;
}
};
template <>
struct std::not_equal_to<glm::vec4> {
bool operator()(const glm::vec4& a, const glm::vec4& b) const {
return a.x != b.x && a.x != b.y && a.z != b.z && a.w != b.w;
}
};
template <>
struct std::not_equal_to<glm::ivec2> {
bool operator()(const glm::ivec2& a, const glm::ivec2& b) const {
return a.x != b.x && a.x != b.y;
}
};
template <>
struct std::not_equal_to<glm::ivec3> {
bool operator()(const glm::ivec3& a, const glm::ivec3& b) const {
return a.x != b.x && a.x != b.y && a.z != b.z;
}
};
template <>
struct std::not_equal_to<glm::ivec4> {
bool operator()(const glm::ivec4& a, const glm::ivec4& b) const {
return a.x != b.x && a.x != b.y && a.z != b.z && a.w != b.w;
}
};
template <>
struct std::not_equal_to<glm::dvec2> {
bool operator()(const glm::dvec2& a, const glm::dvec2& b) const {
return a.x != b.x && a.x != b.y;
}
};
template <>
struct std::not_equal_to<glm::dvec3> {
bool operator()(const glm::dvec3& a, const glm::dvec3& b) const {
return a.x != b.x && a.x != b.y && a.z != b.z;
}
};
template <>
struct std::not_equal_to<glm::dvec4> {
bool operator()(const glm::dvec4& a, const glm::dvec4& b) const {
return a.x != b.x && a.x != b.y && a.z != b.z && a.w != b.w;
}
};
namespace openspace::documentation {
template <>
@@ -756,13 +378,13 @@ TestResult InListVerifier<T>::operator()(const ghoul::Dictionary& dict,
std::string list = std::accumulate(
values.begin() + 1,
values.end(),
fmt::format("{}", values.front()),
std::format("{}", values.front()),
[](std::string lhs, typename T::Type rhs) {
return fmt::format("{}, {}", lhs, rhs);
return std::format("{}, {}", lhs, rhs);
}
);
o.explanation = fmt::format(
"{} not in list of accepted values '{}'",
o.explanation = std::format(
"'{}' not in list of accepted values '{}'",
key, list
);
r.offenses.push_back(o);
@@ -782,12 +404,12 @@ std::string InListVerifier<T>::documentation() const {
std::copy(
values.begin(),
values.end(),
std::ostream_iterator<typename T::Type>(s, ",")
std::ostream_iterator<typename T::Type>(s, ", ")
);
std::string joined = s.str();
// We need to remove a trailing ',' at the end of the string
result += joined.substr(0, joined.size() - 1);
// We need to remove a trailing ',' and whitespace at the end of the string
result += joined.substr(0, joined.size() - 2);
result += " }";
return result;
@@ -800,7 +422,7 @@ NotInListVerifier<T>::NotInListVerifier(std::vector<typename T::Type> vals)
template <typename T>
TestResult NotInListVerifier<T>::operator()(const ghoul::Dictionary& dict,
const std::string& key) const
const std::string& key) const
{
TestResult res = T::operator()(dict, key);
if (res.success) {
@@ -1064,30 +686,11 @@ std::string NotInRangeVerifier<T>::documentation() const {
template <typename T>
AnnotationVerifier<T>::AnnotationVerifier(std::string a)
: annotation(std::move(a))
{
}
{}
template <typename T>
std::string AnnotationVerifier<T>::documentation() const {
return annotation;
}
template <typename T>
TestResult DeprecatedVerifier<T>::operator()(const ghoul::Dictionary& dict,
const std::string& key) const
{
TestResult res = T::operator()(dict, key);
TestResult::Warning w;
w.offender = key;
w.reason = TestResult::Warning::Reason::Deprecated;
res.warnings.push_back(w);
return res;
}
template <typename T>
std::string DeprecatedVerifier<T>::documentation() const {
return T::documentation() + " (deprecated)";
}
} // namespace openspace::documentation

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -34,9 +34,9 @@
#include <string>
#include <vector>
namespace openspace::documentation { struct Documentation; }
namespace openspace {
namespace openspace::configuration {
namespace documentation { struct Documentation; }
struct Configuration {
Configuration() = default;
@@ -45,7 +45,9 @@ struct Configuration {
Configuration& operator=(const Configuration&) = delete;
Configuration& operator=(Configuration&&) = default;
std::string windowConfiguration = "${CONFIG}/single.xml";
ghoul::Dictionary createDictionary();
std::string windowConfiguration = "${CONFIG}/single.json";
std::string asset;
std::string profile;
@@ -76,6 +78,8 @@ struct Configuration {
Logging logging;
std::string scriptLog;
bool verboseScriptLog = false;
int scriptLogRotation = 3;
struct DocumentationInfo {
std::string path;
@@ -88,7 +92,7 @@ struct Configuration {
struct LoadingScreen {
bool isShowingMessages = true;
bool isShowingNodeNames = true;
bool isShowingProgressbar = true;
bool isShowingLogMessages = true;
};
LoadingScreen loadingScreen;
@@ -102,6 +106,8 @@ struct Configuration {
bool shouldUseScreenshotDate = false;
bool sandboxedLua = true;
std::string onScreenTextScaling = "window";
bool usePerProfileCache = false;
@@ -112,6 +118,15 @@ struct Configuration {
bool isConsoleDisabled = false;
bool bypassLauncher = false;
enum LayerServer {
All = 0,
NewYork,
Sweden,
Utah,
None
};
LayerServer layerServer = LayerServer::All;
std::map<std::string, ghoul::Dictionary> moduleConfigurations;
struct OpenGLDebugContext {
@@ -141,15 +156,19 @@ struct Configuration {
// Values not read from the openspace.cfg file
std::string sgctConfigNameInitialized;
static documentation::Documentation Documentation;
static documentation::Documentation Documentation();
ghoul::lua::LuaState state;
};
std::filesystem::path findConfiguration(const std::string& filename = "openspace.cfg");
Configuration loadConfigurationFromFile(const std::filesystem::path& filename,
const glm::ivec2& primaryMonitorResolution, std::string_view overrideScript);
Configuration loadConfigurationFromFile(const std::filesystem::path& configurationFile,
const std::filesystem::path& settingsFile,
const glm::ivec2& primaryMonitorResolution);
} // namespace openspace::configuration
Configuration::LayerServer stringToLayerServer(std::string_view server);
std::string layerServerToString(Configuration::LayerServer server);
} // namespace openspace
#endif // __OPENSPACE_CORE___CONFIGURATION___H__

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -44,7 +44,7 @@ public:
// Since the FileFuture object will be used from multiple threads, we have to be
// careful about the access pattern, that is, no values should be read and written
// by both the DownloadManager and the outside threads.
FileFuture(std::string file);
FileFuture(std::filesystem::path file);
// Values that are written by the DownloadManager to be consumed by others
long long currentSize = -1;
@@ -53,7 +53,7 @@ public:
float secondsRemaining = -1.f;
bool isFinished = false;
bool isAborted = false;
std::string filePath;
std::filesystem::path filePath;
std::string errorMessage;
std::string format;
// Values set by others to be consumed by the DownloadManager
@@ -104,15 +104,14 @@ public:
OverrideFile overrideFile = OverrideFile::Yes,
FailOnError failOnError = FailOnError::No, unsigned int timeout_secs = 0,
DownloadFinishedCallback finishedCallback = DownloadFinishedCallback(),
DownloadProgressCallback progressCallback = DownloadProgressCallback()
);
DownloadProgressCallback progressCallback = DownloadProgressCallback()) const;
std::future<MemoryFile> fetchFile(const std::string& url,
SuccessCallback successCallback = SuccessCallback(),
ErrorCallback errorCallback = ErrorCallback());
void getFileExtension(const std::string& url,
RequestFinishedCallback finishedCallback = RequestFinishedCallback());
void fileExtension(const std::string& url,
RequestFinishedCallback finishedCallback = RequestFinishedCallback()) const;
private:
bool _useMultithreadedDownload;

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -33,6 +33,7 @@ namespace ghoul::fontrendering { class FontManager; }
namespace openspace {
struct Configuration;
class Dashboard;
class DeferredcasterManager;
class DownloadManager;
@@ -50,16 +51,15 @@ class SyncEngine;
class TimeManager;
class VersionChecker;
struct WindowDelegate;
namespace configuration { struct Configuration; }
namespace interaction {
struct JoystickInputStates;
struct WebsocketInputStates;
class ActionManager;
class InteractionMonitor;
class KeybindingManager;
class KeyframeRecordingHandler;
class NavigationHandler;
class SessionRecording;
class ShortcutManager;
class SessionRecordingHandler;
} // namespace interaction
namespace properties { class PropertyOwner; }
namespace scripting {
@@ -88,15 +88,15 @@ inline SyncEngine* syncEngine;
inline TimeManager* timeManager;
inline VersionChecker* versionChecker;
inline WindowDelegate* windowDelegate;
inline configuration::Configuration* configuration;
inline Configuration* configuration;
inline interaction::ActionManager* actionManager;
inline interaction::InteractionMonitor* interactionMonitor;
inline interaction::JoystickInputStates* joystickInputStates;
inline interaction::WebsocketInputStates* websocketInputStates;
inline interaction::KeybindingManager* keybindingManager;
inline interaction::KeyframeRecordingHandler* keyframeRecording;
inline interaction::NavigationHandler* navigationHandler;
inline interaction::SessionRecording* sessionRecording;
inline interaction::ShortcutManager* shortcutManager;
inline interaction::SessionRecordingHandler* sessionRecordingHandler;
inline properties::PropertyOwner* rootPropertyOwner;
inline properties::PropertyOwner* screenSpaceRootPropertyOwner;
inline properties::PropertyOwner* userPropertyOwner;

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -66,11 +66,10 @@ inline std::vector<std::function<void(TouchInput)>>* touchExit;
/**
* If the framerate becomes slow, Chromium Embedded Framework (used in Web Browser Module)
* needs to perform its message loop work more frequently than once per frame. If this
* method is not called frequently enough, the GUI will become much less responsive.
* A future more long-term may decouple the browser's message work loop from the main
* render loop altogehter using a separate thread.
* Currently, this method is called from within the RenderEngine,
* between calls to individual renderables.
* method is not called frequently enough, the GUI will become much less responsive. A
* future more long-term may decouple the browser's message work loop from the main render
* loop altogehter using a separate thread. Currently, this method is called from within
* the RenderEngine, between calls to individual renderables.
*/
extern void (*webBrowserPerformanceHotfix)();

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -43,12 +43,14 @@ namespace documentation { struct Documentation; }
* logfile should be created. Both logs can be customized using the `Append`,
* `TimeStamping`, `DateStamping`, `CategoryStamping`, and `LogLevelStamping` values.
*
* \param dictionary The dictionary from which the ghoul::logging::Log should be created
* \param dictionary The dictionary from which the ghoul::logging::Log should be created
* \return The created ghoul::logging::Log
* \post The return value will not be `nullptr`
* \throw ghoul::RuntimeError If there was an error creating the ghoul::logging::Log
* \sa ghoul::logging::TextLog
* \sa ghoul::logging::HTMLLog
*
* \post The return value will not be `nullptr`
* \throw ghoul::RuntimeError If there was an error creating the ghoul::logging::Log
*
* \see ghoul::logging::TextLog
* \see ghoul::logging::HTMLLog
*/
std::unique_ptr<ghoul::logging::Log> createLog(const ghoul::Dictionary& dictionary);

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -39,15 +39,16 @@ namespace openspace {
class OpenSpaceModule;
namespace documentation { struct Documentation; }
namespace scripting { struct LuaLibrary; }
/**
* The ModuleEngine is the central repository for registering and accessing
* OpenSpaceModule for the current application run. By initializing (#initialize) the
* ModuleEngine, the default set of OpenSpaceModule%s as generated by CMake in the
* `moduleregistration.h` file is automatically registered and created.
* Additional OpenSpaceModule%s can be registered with the #registerModule function, which
* will internally call the OpenSpaceModule::initialize method.
* `moduleregistration.h` file is automatically registered and created. Additional
* OpenSpaceModule%s can be registered with the #registerModule function, which will
* internally call the OpenSpaceModule::initialize method.
*/
class ModuleEngine : public properties::PropertyOwner {
public:
@@ -55,11 +56,10 @@ public:
/**
* Registers all of the OpenSpaceModule%s which are created by the CMake configuration
* and stored in the `moduleregistration.h` file. For all of those modules
* the OpenSpaceModule::initialize method with will called.
* and stored in the `moduleregistration.h` file. For all of those modules the
* OpenSpaceModule::initialize method with will called.
*
* \throw ghoul::RuntimeError If two modules in the default modules have the same
* name
* \throw ghoul::RuntimeError If two modules in the default modules have the same name
*/
void initialize(const std::map<std::string, ghoul::Dictionary>& moduleConfigurations);
@@ -104,7 +104,7 @@ public:
* to have the public static member variable `name` which must be equal to
* the name of the module used in its constructor.
*
* \return a pointer to the module of the given subclass
* \return A pointer to the module of the given subclass
*/
template <class ModuleSubClass>
ModuleSubClass* module() const;
@@ -118,11 +118,16 @@ public:
ghoul::systemcapabilities::Version requiredOpenGLVersion() const;
/**
* Returns the Lua library that contains all Lua functions available to affect the
* modules.
*/
* Returns the Lua library that contains all Lua functions available to affect the
* modules.
*/
static scripting::LuaLibrary luaLibrary();
/**
* Returns the list of all documentations for all modules.
*/
std::vector<documentation::Documentation> moduleDocumentations() const;
private:
/// The list of all names of all registered OpenSpaceModules
properties::StringListProperty _allModules;

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -51,28 +51,35 @@ class Scene;
namespace scripting { struct LuaLibrary; }
// Structure that is responsible for the delayed shutdown of the application
/**
* Structure that is responsible for the delayed shutdown of the application.
*/
struct ShutdownInformation {
// Whether the application is currently in shutdown mode (i.e. counting down the
// timer and closing it at '0'
/// Whether the application is currently in shutdown mode (i.e. counting down the
/// timer and closing it at '0'
bool inShutdown = false;
// Total amount of time the application will wait before actually shutting down
/// Total amount of time the application will wait before actually shutting down
float waitTime = 0.f;
// Current state of the countdown; if it reaches '0', the application will
// close
/// Current state of the countdown; if it reaches '0', the application will
/// close
float timer = 0.f;
};
struct CommandlineArguments {
std::string configurationName;
std::vector<std::string> configurationOverride;
std::optional<std::string> configuration;
std::optional<std::string> windowConfig;
std::optional<std::string> profile;
std::optional<std::string> propertyVisibility;
std::optional<bool> bypassLauncher;
};
class OpenSpaceEngine : public properties::PropertyOwner {
public:
// A mode that specifies which part of the system is currently in control.
// The mode can be used to limit certain features, like setting time, navigation
// or triggering scripts
/**
* A mode that specifies which part of the system is currently in control. The mode
* can be used to limit certain features, like setting time, navigation or triggering
* scripts.
*/
enum class Mode {
UserControl = 0,
SessionRecordingPlayback,
@@ -89,12 +96,10 @@ public:
void deinitializeGL();
void preSynchronization();
void postSynchronizationPreDraw();
void viewportChanged();
void render(const glm::mat4& sceneMatrix, const glm::mat4& viewMatrix,
const glm::mat4& projectionMatrix);
void drawOverlays();
void postDraw();
void resetPropertyChangeFlags();
void keyboardCallback(Key key, KeyModifier mod, KeyAction action,
IsGuiWindow isGuiWindow);
void charCallback(unsigned int codepoint, KeyModifier modifier,
@@ -111,7 +116,6 @@ public:
void decode(std::vector<std::byte> data);
properties::Property::Visibility visibility() const;
bool showHiddenSceneGraphNodes() const;
void toggleShutdownMode();
Mode currentMode() const;
@@ -128,9 +132,11 @@ public:
AssetManager& assetManager();
LoadingScreen* loadingScreen();
void writeDocumentation();
void createUserDirectoriesIfNecessary();
uint64_t ramInUse() const;
uint64_t vramInUse() const;
/**
* Returns the Lua library that contains all Lua functions available to affect the
* application.
@@ -142,17 +148,14 @@ private:
void loadFonts();
void runGlobalCustomizationScripts();
void resetPropertyChangeFlagsOfSubowners(openspace::properties::PropertyOwner* po);
properties::BoolProperty _printEvents;
properties::OptionProperty _visibility;
properties::BoolProperty _showHiddenSceneGraphNodes;
properties::FloatProperty _fadeOnEnableDuration;
properties::BoolProperty _disableAllMouseInputs;
std::unique_ptr<Scene> _scene;
std::unique_ptr<AssetManager> _assetManager;
bool _shouldAbortLoading = false;
std::unique_ptr<LoadingScreen> _loadingScreen;
std::unique_ptr<VersionChecker> _versionChecker;
@@ -177,7 +180,8 @@ private:
* Sets the camera position using the time contents of a profile. The function will
* set an absolute position or a go-to-geolocation command using the globebrowsing
* module.
* \param p The Profile to be read.
*
* \param p The Profile to be read
*/
void setCameraFromProfile(const Profile& p);
@@ -185,21 +189,21 @@ void setCameraFromProfile(const Profile& p);
* Reads a list of modules from a profile, and executes scripts based on whether or
* not the corresponding module is loaded.
*
* \param p The Profile to be read.
* \param p The Profile to be read
*/
void setModulesFromProfile(const Profile& p);
/**
* Registers actions from the contents of a profile.
*
* \param p The Profile to be read.
* \param p The Profile to be read
*/
void setActionsFromProfile(const Profile& p);
/**
* Registers keybindings from the contents of a profile.
*
* \param p The Profile to be read.
* \param p The Profile to be read
*/
void setKeybindingsFromProfile(const Profile& p);
@@ -208,7 +212,7 @@ void setKeybindingsFromProfile(const Profile& p);
* If any nodes are listed, a script to mark these will be queued with the
* script engine.
*
* \param p The Profile to be read.
* \param p The Profile to be read
*/
void setMarkInterestingNodesFromProfile(const Profile& p);
@@ -217,7 +221,7 @@ void setMarkInterestingNodesFromProfile(const Profile& p);
* at the end of the initialization. Any openspace lua commands are allowed,
* and will be added to the script queue.
*
* \param p The Profile to be read.
* \param p The Profile to be read
*/
void setAdditionalScriptsFromProfile(const Profile& p);

View File

@@ -0,0 +1,64 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2025 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___SETTINGS___H__
#define __OPENSPACE_CORE___SETTINGS___H__
#include <openspace/engine/configuration.h>
#include <openspace/properties/property.h>
#include <filesystem>
#include <optional>
namespace openspace {
struct Settings {
auto operator<=>(const Settings&) const = default;
std::optional<bool> hasStartedBefore;
std::optional<std::string> configuration;
std::optional<bool> rememberLastConfiguration;
std::optional<std::string> profile;
std::optional<bool> rememberLastProfile;
std::optional<properties::Property::Visibility> visibility;
std::optional<bool> bypassLauncher;
std::optional<Configuration::LayerServer> layerServer;
struct MRF {
auto operator<=>(const MRF&) const = default;
std::optional<bool> isEnabled;
std::optional<std::string> location;
};
MRF mrf;
};
std::filesystem::path findSettings(const std::string& filename = "settings.json");
Settings loadSettings(const std::filesystem::path& filename = findSettings());
void saveSettings(const Settings& settings, const std::filesystem::path& filename);
} // namespace openspace
#endif // __OPENSPACE_CORE___SETTINGS___H__

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -36,72 +36,71 @@ namespace openspace {
class Syncable;
/**
* Manages a collection of `Syncable`s and ensures they are synchronized
* over SGCT nodes. Encoding/Decoding order is handles internally.
* Manages a collection of `Syncable`s and ensures they are synchronized over SGCT nodes.
* Encoding/Decoding order is handles internally.
*/
class SyncEngine {
public:
BooleanType(IsMaster);
/**
* Creates a new SyncEngine which a buffer size of \p syncBufferSize
* Creates a new SyncEngine which a buffer size of \p syncBufferSize.
*
* \pre syncBufferSize must be bigger than 0
*/
SyncEngine(unsigned int syncBufferSize);
/**
* Encodes all added Syncables in the injected `SyncBuffer`.
* This method is only called on the SGCT master node
* Encodes all added Syncables in the injected `SyncBuffer`. This method is only
* called on the SGCT master node.
*/
std::vector<std::byte> encodeSyncables();
/**
* Decodes the `SyncBuffer` into the added Syncables.
* This method is only called on the SGCT client nodes
* Decodes the `SyncBuffer` into the added Syncables. This method is only called on
* the SGCT client nodes.
*/
void decodeSyncables(std::vector<std::byte> data);
/**
* Invokes the presync method of all added Syncables
* Invokes the presync method of all added Syncables.
*/
void preSynchronization(IsMaster isMaster);
/**
* Invokes the postsync method of all added Syncables
* Invokes the postsync method of all added Syncables.
*/
void postSynchronization(IsMaster isMaster);
/**
* Add a Syncable to be synchronized over the SGCT cluster.
* \pre syncable must not be nullptr
*
* \pre syncable must not be `nullptr`
*/
void addSyncable(Syncable* syncable);
/**
* Add multiple Syncables to be synchronized over the SGCT cluster
* Add multiple Syncables to be synchronized over the SGCT cluster.
*
* \pre syncables must not contain any nullptr
*/
void addSyncables(const std::vector<Syncable*>& syncables);
/**
* Remove a Syncable from being synchronized over the SGCT cluster
* Remove a Syncable from being synchronized over the SGCT cluster.
*/
void removeSyncable(Syncable* syncable);
/**
* Remove multiple Syncables from being synchronized over the SGCT cluster
* Remove multiple Syncables from being synchronized over the SGCT cluster.
*/
void removeSyncables(const std::vector<Syncable*>& syncables);
private:
/**
* Vector of Syncables. The vectors ensures consistent encode/decode order
*/
/// Vector of Syncables. The vectors ensures consistent encode/decode order.
std::vector<Syncable*> _syncables;
/**
* Databuffer used in encoding/decoding
*/
/// Databuffer used in encoding/decoding
SyncBuffer _syncBuffer;
};

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -34,6 +34,9 @@ namespace openspace {
struct WindowDelegate {
enum class Frustum { Mono, LeftEye, RightEye };
enum class Cursor { Arrow, IBeam, CrossHair, PointingHand, ResizeEW, ResizeNS,
ResizeNWSE, ResizeNESW, ResizeAll, NotAllowed };
void (*terminate)() = [](){};
void (*setBarrier)(bool enabled) = [](bool) {};
@@ -114,7 +117,7 @@ struct WindowDelegate {
uint64_t (*swapGroupFrameNumber)() = []() { return uint64_t(0); };
void (*setScreenshotFolder)(std::string) = [](std::string) {};
void (*setScreenshotFolder)(std::filesystem::path) = [](std::filesystem::path) {};
void (*showStatistics)(bool) = [](bool) {};
@@ -122,8 +125,12 @@ struct WindowDelegate {
int (*currentNode)() = []() { return 0; };
glm::vec2 (*mousePositionViewportRelative)(glm::vec2 mousePosition) =
[](glm::vec2) { return glm::vec2(0); };
glm::vec2 (*mousePositionViewportRelative)(const glm::vec2& mousePosition) =
[](const glm::vec2&) { return glm::vec2(0); };
void (*setStatisticsGraphScale)(float scale) = [](float) {};
void (*setMouseCursor)(Cursor cursor) = [](Cursor) {};
};
} // namespace openspace

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -58,21 +58,20 @@ struct Event {
// if they are triggered by events
// 6. Add the new enum entry into the `toString` and `fromString` methods
enum class Type : uint8_t {
SceneGraphNodeAdded,
SceneGraphNodeRemoved,
ParallelConnection,
ProfileLoadingFinished,
AssetLoadingFinished,
ApplicationShutdown,
ScreenSpaceRenderableAdded,
ScreenSpaceRenderableRemoved,
CameraFocusTransition,
TimeOfInterestReached,
MissionEventReached,
PlanetEclipsed,
InterpolationFinished,
FocusNodeChanged,
LayerAdded,
LayerRemoved,
PropertyTreeUpdated,
PropertyTreePruned,
ActionAdded,
ActionRemoved,
SessionRecordingPlayback,
PointSpacecraft,
RenderableEnabled,
@@ -80,7 +79,10 @@ struct Event {
CameraPathStarted,
CameraPathFinished,
CameraMovedPosition,
Custom
ScheduledScriptExecuted,
GuiTreeUpdated,
Custom,
Last // sentinel value
};
constexpr explicit Event(Type type_) : type(type_) {}
@@ -110,43 +112,6 @@ void logAllEvents(const Event* e);
// Events
//
/**
* This event is created whenever a new scene graph node is added to the system. By the
* time this event is signalled, the scene graph node has already been created and added
* to the scene.
*/
struct EventSceneGraphNodeAdded : public Event {
static constexpr Type Type = Event::Type::SceneGraphNodeAdded;
/**
* Creates an instance of an EventSceneGraphNodeAdded event.
*
* \param node_ The identifier of the node that was added
*
* \pre node_ must not be nullptr
*/
explicit EventSceneGraphNodeAdded(const SceneGraphNode* node_);
const tstring node;
};
/**
* This event is created whenever a scene graph node was removed. By the time this event
* is signalled, the scene graph node has already been removed.
*/
struct EventSceneGraphNodeRemoved : public Event {
static constexpr Type Type = Event::Type::SceneGraphNodeRemoved;
/**
* Creates an instance of an EventSceneGraphNodeRemoved event.
*
* \param node_ The identifier of the node that was removed
*
* \pre node_ must not be nullptr
*/
explicit EventSceneGraphNodeRemoved(const SceneGraphNode* node_);
const tstring node;
};
/**
* This event is created whenever something in the parallel connection subsystem changes.
* The new state is sent as an argument with this event.
@@ -164,7 +129,7 @@ struct EventParallelConnection : public Event {
/**
* Creates an instance of an EventParallelConnection event.
*
* \param state_ The new state of the parallel connection system; is one of
* \param state_ The new state of the parallel connection system; is one of
* `Established`, `Lost`, `HostshipGained`, or `HostshipLost`
*/
explicit EventParallelConnection(State state_);
@@ -184,6 +149,20 @@ struct EventProfileLoadingFinished : public Event {
EventProfileLoadingFinished();
};
/**
* This event is created when the loading of all assets are finished. This is emitted
* regardless of whether it is the initial startup of a profile, or any subsequent asset
* being loaded e.g., through add or drag-and-drop.
*/
struct EventAssetLoadingFinished : public Event {
static constexpr Type Type = Event::Type::AssetLoadingFinished;
/**
* Creates an instance of an AssetLoadingFinished event.
*/
EventAssetLoadingFinished();
};
/**
* This event is created whenever some information about the application shutdown sequence
* changes. This can either be that the seqeuence started, was aborted, or is finished,
@@ -201,65 +180,30 @@ struct EventApplicationShutdown : public Event {
/**
* Creates an instance of an EventApplicationShutdown event.
*
* \param state_ The next state of the application shutdown sequence; is one of
* `Started`, `Aborted`, or `Finished`
* \param state_ The next state of the application shutdown sequence; is one of
* `Started`, `Aborted`, or `Finished`
*/
explicit EventApplicationShutdown(State state_);
const State state;
};
/**
* This event is created when a new screenspace renderable has been created. By the time
* this event is craeted, the screenspace renderable is already registered and available.
*/
struct EventScreenSpaceRenderableAdded : public Event {
static constexpr Type Type = Event::Type::ScreenSpaceRenderableAdded;
/**
* Creates an instance of an EventScreenSpaceRenderableAdded event.
*
* \param renderable_ The the new screenspace renderable that was added to the system
*
* \pre renderable_ must not be nullptr
*/
explicit EventScreenSpaceRenderableAdded(const ScreenSpaceRenderable* renderable_);
const tstring renderable;
};
/**
* This event is created when a screenspace renderable has been removed from the system.
* When this event is created, the screenspace renderable has already been removed and is
* no longer available
*/
struct EventScreenSpaceRenderableRemoved : public Event {
static constexpr Type Type = Event::Type::ScreenSpaceRenderableRemoved;
/**
* Creates an instance of an EventScreenSpaceRenderableRemoved event.
*
* \param renderable_ The the new screenspace renderable that was removed
*/
explicit EventScreenSpaceRenderableRemoved(const ScreenSpaceRenderable* renderable_);
const tstring renderable;
};
/**
* This event is created when the camera transitions between different interaction sphere
* distances. Right now, only movement relative to camera's focus node is considered.
* Each scene graph node has an interaction sphere radius that serves as the reference
* distance for all spheres.
```
Diagram of events for a camera moving from right-to-left. Interaction sphere is 'O' in
middle, and ')' are spherical boundaries. The approach factor, reach factor, and
interaction sphere radius are all taken from the current focus node.
|<------------------->| Approach factor * Interaction sphere
|<------>| Reach Factor * Interaction sphere
( ( O ) )
^ ^ ^ ^
Exiting Receding Reaching Approaching
```
* ```
* Diagram of events for a camera moving from right-to-left. Interaction sphere is 'O' in
* middle, and ')' are spherical boundaries. The approach factor, reach factor, and
* interaction sphere radius are all taken from the current focus node.
*
* |<------------------->| Approach factor * Interaction sphere
* |<------>| Reach Factor * Interaction sphere
*
* ( ( O ) )
* ^ ^ ^ ^
* Exiting Receding Reaching Approaching
* ```
*/
struct EventCameraFocusTransition : public Event {
static constexpr Type Type = Event::Type::CameraFocusTransition;
@@ -347,7 +291,7 @@ struct EventPlanetEclipsed : public Event {
/**
* This event is created when the interpolation of a property value is finished. If the
* interpolation time of a property change is 0s, this event is not fired
* interpolation time of a property change is 0s, this event is not fired.
*/
struct EventInterpolationFinished : public Event {
static constexpr Type Type = Event::Type::InterpolationFinished;
@@ -387,53 +331,76 @@ struct EventFocusNodeChanged : public Event {
};
/**
* This event is created when a layer is added to to a globe.
* This event is created a property owner or property has been added or has changed.
*/
struct EventLayerAdded : public Event {
static constexpr Type Type = Event::Type::LayerAdded;
struct EventPropertyTreeUpdated : public Event {
static constexpr Type Type = Event::Type::PropertyTreeUpdated;
/**
* Creates an instance of an EventLayerAdded event.
* Creates an instance of an EventPropertyTreeUpdated event.
*
* \param node_ The identifier of the globe to which the layer is added
* \param layerGroup_ The identifier of the layer group to which the layer is added
* \param layer_ The identifier of the layer that was added
* \param uri_ A string with the uri of the property or property owner that was added
*
* \pre node_ must not be empty
* \pre layerGroup_ must not be empty
* \pre layer_ must not be empty
* \pre uri_ must be a valid uri
*/
explicit EventLayerAdded(std::string_view node_, std::string_view layerGroup_,
std::string_view layer_);
explicit EventPropertyTreeUpdated(std::string_view uri_);
const tstring node;
const tstring layerGroup;
const tstring layer;
const tstring uri;
};
/**
* This event is created when a layer is removed from a globe.
* This event is created when a property owner or property is removed from a the property
* tree.
*/
struct EventLayerRemoved : public Event {
static constexpr Type Type = Event::Type::LayerRemoved;
struct EventPropertyTreePruned : public Event {
static constexpr Type Type = Event::Type::PropertyTreePruned;
/**
* Creates an instance of an EventLayerRemoved event.
* Creates an instance of an EventPropertyTreePruned event.
*
* \param node_ The identifier of the globe to which the layer is removed
* \param layerGroup_ The identifier of the layer group to which the layer is removed
* \param layer_ The identifier of the layer that was removed
* \param uri_ The uri of the property or property owner that was removed
*
* \pre node_ must not be empty
* \pre layerGroup_ must not be empty
* \pre layer_ must not be empty
* \pre uri_ must be a valid uri
*/
explicit EventLayerRemoved(std::string_view node_, std::string_view layerGroup_,
std::string_view layer_);
explicit EventPropertyTreePruned(std::string_view uri_);
const tstring node;
const tstring layerGroup;
const tstring layer;
const tstring uri;
};
/**
* This event is created when an action is added.
*/
struct EventActionAdded : public Event {
static constexpr Type Type = Event::Type::ActionAdded;
/**
* Creates an instance of an EventActionAdded event.
*
* \param uri_ A string with the uri of the action that was added
*
* \pre uri_ must be a valid uri
*/
explicit EventActionAdded(std::string_view uri_);
const tstring uri;
};
/**
* This event is created when an action is removed.
*/
struct EventActionRemoved : public Event {
static constexpr Type Type = Event::Type::ActionRemoved;
/**
* Creates an instance of an EventActionRemoved event.
*
* \param uri_ The uri of the action that was removed
*
* \pre uri_ must be a valid uri
*/
explicit EventActionRemoved(std::string_view uri_);
const tstring uri;
};
/**
@@ -562,7 +529,7 @@ struct EventCameraPathFinished : public Event {
};
/**
* This event is created when the a camera moves location
* This event is created when the a camera moves location.
*/
struct EventCameraMovedPosition : public Event {
static constexpr Type Type = Event::Type::CameraMovedPosition;
@@ -573,6 +540,33 @@ struct EventCameraMovedPosition : public Event {
EventCameraMovedPosition();
};
/**
* This event is created when a scheduled script is executed.
*/
struct EventScheduledScriptExecuted : public Event {
static constexpr Type Type = Event::Type::ScheduledScriptExecuted;
/**
* Creates an instance of an ScheduledScriptExecuted event.
*/
EventScheduledScriptExecuted(std::string_view script_);
const tstring script;
};
/**
* This event is created when the custom ordering for a specific branch in the Scene
* GUI tree is changed. It signals to the UI that the tree should be updated.
*/
struct EventGuiTreeUpdated : public Event {
static constexpr Type Type = Event::Type::GuiTreeUpdated;
/**
* Creates an instance of an EventGuiTreeUpdated event.
*/
EventGuiTreeUpdated();
};
/**
* A custom event type that can be used in a pinch when no explicit event type is
* available. This should only be used in special circumstances and it should be

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -36,6 +36,8 @@ namespace events { struct Event; }
class EventEngine {
public:
using ScriptCallback = std::function<void(ghoul::Dictionary)>;
struct ActionInfo {
events::Event::Type type;
uint32_t id = std::numeric_limits<uint32_t>::max();
@@ -44,11 +46,16 @@ public:
std::optional<ghoul::Dictionary> filter;
};
struct TopicInfo {
uint32_t id = std::numeric_limits<uint32_t>::max();
ScriptCallback callback;
};
/**
* This function returns the first event stored in the EventEngine, or `nullptr` if
* no event exists. To navigate the full list of events, you can access the returned
* Event's next function. If the end of the list is reached, the next pointer will be
* a nullptr
* a `nullptr`.
*
* \return The first event stored in the EventEngine or nullptr if no event exists
*/
@@ -57,11 +64,11 @@ public:
/**
* Publish a new event of type T by providing optional arguments Args to the Event's
* constructor. An example of usage is
* `engine.publishEvent<MyEvent>("a", 2.0);` which would call the
* constructor of `MyEvent` with a `const char*` and `double` parameter.
* `engine.publishEvent<MyEvent>("a", 2.0);` which would call the constructor of
* `MyEvent` with a `const char*` and `double` parameter.
*
* \param args The arguments that are passed to the constructor of T
* \tparam T The subclass of Event that is to be published
* \param args The arguments that are passed to the constructor of T
*/
template <typename T, typename... Args>
void publishEvent(Args&&... args);
@@ -87,6 +94,16 @@ public:
void registerEventAction(events::Event::Type type, std::string identifier,
std::optional<ghoul::Dictionary> filter = std::nullopt);
/**
* Registers a new topic for a specific event type.
*
* \param topicId The id of the topic that will be triggered
* \param type The type for which a new topic is registered
* \param callback The callback function that will be called on triggered event
*/
void registerEventTopic(size_t topicId, events::Event::Type type,
ScriptCallback callback);
/**
* Removing registration for a type/action combination.
*
@@ -96,15 +113,24 @@ public:
*/
void unregisterEventAction(events::Event::Type type,
const std::string& identifier,
std::optional<ghoul::Dictionary> filter = std::nullopt);
const std::optional<ghoul::Dictionary>& filter = std::nullopt);
/**
* Removing registration for a specific event identified by the \p identifier.
*
* \param identifier The unique identifier of the event that should be removed.
* \param identifier The unique identifier of the event that should be removed
*/
void unregisterEventAction(uint32_t identifier);
/**
* Removing registration for a topic/type combination, does nothing if topicId or type
* combination does not exist
*
* \param topicId The id of the topic that should be unregistered
* \param type The type of the topic that should be unregistered
*/
void unregisterEventTopic(size_t topicId, events::Event::Type type);
/**
* Returns the list of all registered actions, sorted by their identifiers.
*
@@ -112,6 +138,14 @@ public:
*/
std::vector<ActionInfo> registeredActions() const;
/**
* Returns the list of all registered actions, grouped by their event type.
*
* \return The unordered map of all registered actions
*/
const std::unordered_map<events::Event::Type, std::vector<ActionInfo>>&
eventActions() const;
/**
* Enables the event identified by the \p identifier. If the event is already enabled,
* this function does nothing.
@@ -130,10 +164,16 @@ public:
/**
* Triggers all actions that are registered for events that are in the current event
* queue
* queue.
*/
void triggerActions() const;
/**
* Triggers all topics that are registered for events that are in the current event
* queue.
*/
void triggerTopics() const;
static scripting::LuaLibrary luaLibrary();
private:
@@ -144,12 +184,13 @@ private:
/// The last event in the chain of events stored in the memory pool
events::Event* _lastEvent = nullptr;
// The type is duplicated in the ActionInfo as well, but we want it in the ActionInfo
// to be able to return them to a caller and we want it in this unordered_map to make
// the lookup really fast. So having this extra wasted memory is probably worth it
/// The type is duplicated in the ActionInfo as well, but we want it in the ActionInfo
/// to be able to return them to a caller and we want it in this unordered_map to make
/// the lookup really fast. So having this extra wasted memory is probably worth it
std::unordered_map<events::Event::Type, std::vector<ActionInfo>> _eventActions;
std::unordered_map<events::Event::Type, std::vector<TopicInfo>> _eventTopics;
static uint32_t nextRegisteredEventId;
#ifdef _DEBUG

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -63,7 +63,7 @@ struct Action {
/// current OpenSpace instance. If it is `No`, it is synchronized to other OpenSpace
/// instances, for example other nodes in a cluster environment, or to other OpenSpace
/// instances using a parallel connection
IsLocal isLocal = IsLocal::Yes;
IsLocal isLocal = IsLocal::No;
};
} // namespace openspace::interaction

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -35,14 +35,18 @@ namespace openspace::interaction {
class ActionManager {
public:
BooleanType(ShouldBeSynchronized);
BooleanType(ShouldBeLogged);
bool hasAction(const std::string& identifier) const;
void registerAction(Action action);
void removeAction(const std::string& identifier);
const Action& action(const std::string& identifier) const;
std::vector<Action> actions() const;
void triggerAction(const std::string& identifier,
const ghoul::Dictionary& arguments) const;
void triggerAction(const std::string& identifier, const ghoul::Dictionary& arguments,
ShouldBeSynchronized shouldBeSynchronized,
ShouldBeLogged shouldBeLogged = ShouldBeLogged::No) const;
static scripting::LuaLibrary luaLibrary();
private:

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -33,9 +33,9 @@ namespace openspace::interaction {
class CameraInteractionStates {
public:
/**
* \param sensitivity
* \param velocityScaleFactor can be set to 60 to remove the inertia of the
* interaction. Lower value will make it harder to move the camera.
* \param sensitivity Interaction sensitivity
* \param velocityScaleFactor Can be set to 60 to remove the inertia of the
* interaction. Lower value will make it harder to move the camera
*/
CameraInteractionStates(double sensitivity, double velocityScaleFactor);
virtual ~CameraInteractionStates() = default;
@@ -54,11 +54,11 @@ public:
void resetVelocities();
/*
* Returns true if any of the velocities are larger than zero,
* i.e. wether an interaction happened
/**
* Returns true if any of the velocities are larger than zero, i.e. wether an
* interaction happened.
*/
bool hasNonZeroVelocities(bool checkOnlyMovement = false);
bool hasNonZeroVelocities(bool checkOnlyMovement = false) const;
protected:
struct InteractionState {

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -28,9 +28,9 @@
namespace openspace::interaction {
/**
* Class that acts as a smoothing filter to a variable. The filter has a step
* response on a form that resembles the function y = 1-e^(-t/scale). The variable
* will be updated as soon as it is set to a value (calling the set() function).
* Class that acts as a smoothing filter to a variable. The filter has a step response on
* a form that resembles the function y = 1-e^(-t/scale). The variable will be updated as
* soon as it is set to a value (calling the set() function).
*/
template <typename T, typename ScaleType>
class DelayedVariable {

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -52,7 +52,7 @@ public:
/*
* Called from all places we want to mark activity from. Updates the last registered
* interaction time
* interaction time.
*/
void markInteraction();

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -29,7 +29,7 @@
namespace openspace::interaction {
/*
/**
* Interpolates a typename T using a transfer function.
*/
template <typename T>

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -59,7 +59,7 @@ void Interpolator<T>::setInterpolationTime(float interpolationTime) {
template <typename T>
void Interpolator<T>::step() {
_t += _scaledDeltaTime;
_t = glm::clamp(_t, 0.0f, 1.0f);
_t = glm::clamp(_t, 0.f, 1.f);
}
template <typename T>

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -88,14 +88,14 @@ public:
void updateStateFromInput(
const JoystickInputStates& joystickInputStates, double deltaTime);
void setAxisMapping(std::string joystickName, int axis, AxisType mapping,
void setAxisMapping(const std::string& joystickName, int axis, AxisType mapping,
AxisInvert shouldInvert = AxisInvert::No,
JoystickType joystickType = JoystickType::JoystickLike,
bool isSticky = false, AxisFlip shouldFlip = AxisFlip::No,
double sensitivity = 0.0
);
void setAxisMappingProperty(std::string joystickName, int axis,
void setAxisMappingProperty(const std::string& joystickName, int axis,
std::string propertyUri, float min = 0.f, float max = 1.f,
AxisInvert shouldInvert = AxisInvert::No, bool isRemote = true
);
@@ -163,19 +163,19 @@ inline std::string to_string(
{
using T = openspace::interaction::JoystickCameraStates::AxisType;
switch (value) {
case T::None: return "None";
case T::OrbitX: return "Orbit X";
case T::OrbitY: return "Orbit Y";
case T::ZoomIn: return "Zoom In";
case T::ZoomOut: return "Zoom Out";
case T::Zoom: return "Zoom In and Out";
case T::None: return "None";
case T::OrbitX: return "Orbit X";
case T::OrbitY: return "Orbit Y";
case T::ZoomIn: return "Zoom In";
case T::ZoomOut: return "Zoom Out";
case T::Zoom: return "Zoom In and Out";
case T::LocalRoll: return "LocalRoll";
case T::GlobalRoll: return "GlobalRoll";
case T::PanX: return "Pan X";
case T::PanY: return "Pan Y";
case T::Property: return "Property";
default: return "";
}
case T::PanX: return "Pan X";
case T::PanY: return "Pan Y";
case T::Property: return "Property";
default: return "";
}
}
template <>
@@ -196,7 +196,7 @@ from_string(std::string_view string)
if (string == "Pan Y") { return T::PanY; }
if (string == "Property") { return T::Property; }
throw RuntimeError("Unkonwn axis type '" + std::string(string) + "'");
throw RuntimeError(std::format("Unknown axis type '{}'", string), "Joystick");
}
template <>
@@ -220,7 +220,7 @@ from_string(std::string_view string)
if (string == "JoystickLike") { return T::JoystickLike; }
if (string == "TriggerLike") { return T::TriggerLike; }
throw RuntimeError("Unkonwn joystick type '" + std::string(string) + "'");
throw RuntimeError(std::format("Unknown joystick type '{}'", string), "Joystick");
}
} // namespace ghoul

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -25,10 +25,10 @@
#ifndef __OPENSPACE_CORE___JOYSTICKINPUTSTATE___H__
#define __OPENSPACE_CORE___JOYSTICKINPUTSTATE___H__
#include <ghoul/format.h>
#include <ghoul/misc/assert.h>
#include <ghoul/misc/exception.h>
#include <ghoul/misc/stringconversion.h>
#include <ghoul/fmt.h>
#include <array>
#include <memory>
#include <string>
@@ -37,7 +37,7 @@ namespace openspace::interaction {
/**
* Actions that any button of a joystick can have. Each button must be in one of these
* states
* states.
*/
enum class JoystickAction : uint8_t {
/// Idle state if the button is unpressed and has been unpressed since last frame
@@ -81,7 +81,7 @@ struct JoystickInputStates : public std::array<JoystickInputState, MaxJoysticks>
static constexpr int MaxNumJoysticks = 16;
/**
* This function return the number of axes the joystick with the given name has
* This function return the number of axes the joystick with the given name has.
*
* \param joystickName The name of the joystick to check how many axes it has,
* if empty the max number of axes for all joysticks are returned
@@ -90,7 +90,7 @@ struct JoystickInputStates : public std::array<JoystickInputState, MaxJoysticks>
int numAxes(const std::string& joystickName = "") const;
/**
* This function return the number of buttons the joystick with the given name has
* This function return the number of buttons the joystick with the given name has.
*
* \param joystickName The name of the joystick to check how many buttons it has,
* if empty the max number of buttons for all joysticks are returned
@@ -150,7 +150,7 @@ constexpr openspace::interaction::JoystickAction from_string(std::string_view st
if (string == "Repeat") { return openspace::interaction::JoystickAction::Repeat; }
if (string == "Release") { return openspace::interaction::JoystickAction::Release; }
throw RuntimeError(fmt::format("Unknown action '{}'", string));
throw RuntimeError(std::format("Unknown action '{}'", string));
}
} // namespace ghoul

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -38,8 +38,6 @@ namespace openspace::interaction {
class KeybindingManager {
public:
KeybindingManager();
void resetKeyBindings();
void bindKey(Key key, KeyModifier modifier, std::string action);
@@ -53,8 +51,6 @@ public:
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
nlohmann::json generateJson() const;
const std::multimap<KeyWithModifier, std::string>& keyBindings() const;
private:

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -22,51 +22,41 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___KEYFRAMERECORDINGHANDLER___H__
#define __OPENSPACE_CORE___KEYFRAMERECORDINGHANDLER___H__
#include <openspace/properties/propertyowner.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/scripting/lualibrary.h>
#include <filesystem>
#include <string>
#include <vector>
namespace openspace::interaction {
template <class T>
T nextKeyframeObj(unsigned int index, const std::vector<T>& keyframeContainer,
std::function<void()> finishedCallback)
{
if (index >= (keyframeContainer.size() - 1)) {
if (index == (keyframeContainer.size() - 1)) {
finishedCallback();
}
return keyframeContainer.back();
}
else if (index < keyframeContainer.size()) {
return keyframeContainer[index];
}
else {
return keyframeContainer.back();
}
}
class KeyframeRecordingHandler : public properties::PropertyOwner {
public:
KeyframeRecordingHandler();
template <class T>
T prevKeyframeObj(unsigned int index, const std::vector<T>& keyframeContainer) {
if (index >= keyframeContainer.size()) {
return keyframeContainer.back();
}
else if (index > 0) {
return keyframeContainer[index - 1];
}
else {
return keyframeContainer.front();
}
}
void newSequence();
void addCameraKeyframe(double sequenceTime);
void addScriptKeyframe(double sequenceTime, std::string script);
void removeKeyframe(int index);
void updateKeyframe(int index);
void moveKeyframe(int index, double sequenceTime);
void saveSequence(std::filesystem::path filename);
void loadSequence(std::filesystem::path filename);
void play();
bool hasKeyframeRecording() const;
std::vector<ghoul::Dictionary> keyframes() const;
template <typename T>
T readFromPlayback(std::ifstream& stream) {
T res;
stream.read(reinterpret_cast<char*>(&res), sizeof(T));
return res;
}
static openspace::scripting::LuaLibrary luaLibrary();
template <typename T>
T readFromPlayback(std::stringstream& stream) {
T res;
stream.read(reinterpret_cast<char*>(&res), sizeof(T));
return res;
}
private:
SessionRecording _timeline;
};
} // namespace openspace::interaction
} // namespace openspace
#endif // __OPENSPACE_CORE___KEYFRAMERECORDINGHANDLER___H__

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -36,8 +36,8 @@ class MouseCameraStates : public CameraInteractionStates {
public:
MouseCameraStates(double sensitivity, double velocityScaleFactor);
void updateStateFromInput(const MouseInputState& mouseinputState,
const KeyboardInputState& keyboardinputState, double deltaTime);
void updateStateFromInput(const MouseInputState& mouseState,
const KeyboardInputState& keyboardState, double deltaTime);
void setInvertMouseButton(bool value);

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -25,868 +25,62 @@
#ifndef __OPENSPACE_CORE___SESSIONRECORDING___H__
#define __OPENSPACE_CORE___SESSIONRECORDING___H__
#include <openspace/properties/propertyowner.h>
#include <openspace/navigation/keyframenavigator.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/scripting/lualibrary.h>
#include <ghoul/misc/dictionary.h>
#include <filesystem>
#include <functional>
#include <string>
#include <variant>
#include <vector>
#include <chrono>
namespace openspace::interaction {
struct ConversionError : public ghoul::RuntimeError {
explicit ConversionError(std::string msg);
enum class DataMode {
Ascii = 0,
Binary
};
class SessionRecording : public properties::PropertyOwner {
public:
struct SessionRecording {
struct Entry {
auto operator<=>(const SessionRecording::Entry&) const = default;
inline static const std::string FileHeaderTitle = "OpenSpace_record/playback";
inline static const std::string HeaderCameraAscii = "camera";
inline static const std::string HeaderTimeAscii = "time";
inline static const std::string HeaderScriptAscii = "script";
inline static const std::string HeaderCommentAscii = "#";
inline static const char HeaderCameraBinary = 'c';
inline static const char HeaderTimeBinary = 't';
inline static const char HeaderScriptBinary = 's';
inline static const std::string FileExtensionBinary = ".osrec";
inline static const std::string FileExtensionAscii = ".osrectxt";
using Camera = KeyframeNavigator::CameraPose;
using Script = std::string;
enum class DataMode {
Ascii = 0,
Binary,
Unknown
double timestamp = 0.0;
double simulationTime = 0.0;
std::variant<Camera, Script> value;
};
enum class SessionState {
Idle = 0,
Recording,
Playback,
PlaybackPaused
};
struct Timestamps {
double timeOs;
double timeRec;
double timeSim;
};
/*
* Struct for storing a script substring that, if found in a saved script,
* will be replaced by its substringReplacement counterpart.
*/
struct ScriptSubstringReplace {
std::string substringFound;
std::string substringReplacement;
ScriptSubstringReplace(std::string found, std::string replace)
: substringFound(found)
, substringReplacement(replace) {}
};
static const size_t FileHeaderVersionLength = 5;
char FileHeaderVersion[FileHeaderVersionLength+1] = "01.00";
char TargetConvertVersion[FileHeaderVersionLength+1] = "01.00";
static const char DataFormatAsciiTag = 'A';
static const char DataFormatBinaryTag = 'B';
static const size_t keyframeHeaderSize_bytes = 33;
static const size_t saveBufferCameraSize_min = 82;
static const size_t saveBufferStringSize_max = 2000;
static const size_t _saveBufferMaxSize_bytes = keyframeHeaderSize_bytes +
+ saveBufferCameraSize_min + saveBufferStringSize_max;
using CallbackHandle = int;
using StateChangeCallback = std::function<void()>;
SessionRecording();
SessionRecording(bool isGlobal);
~SessionRecording() override;
/**
* Used to de-initialize the session recording feature. Any recording or playback
* in progress will be stopped, files closed, and keyframes in memory deleted.
*/
void deinitialize();
/**
* This is called with every rendered frame. If in recording state, the camera
* state will be saved to the recording file (if its state has changed since last).
* If in playback state, the next keyframe will be used (if it is time to do so).
*/
void preSynchronization();
/**
* If enabled, calling this function will render information about the session
* recording that is currently taking place to the screen.
*/
void render();
/**
* Current time based on playback mode
*/
double currentTime() const;
/**
* Fixed delta time set by user for use during saving of frame during playback mode
*/
double fixedDeltaTimeDuringFrameOutput() const;
/**
* Returns the number of microseconds that have elapsed since playback started, if
* playback is set to be in the mode where a screenshot is captured with every
* rendered frame (enableTakeScreenShotDuringPlayback() is used to enable this mode).
* At the start of playback, this timer is set to the current steady_clock value.
* However, during playback it is incremented by the fixed framerate of the playback
* rather than the actual clock value (as in normal operation).
*
* \returns number of microseconds elapsed since playback started in terms of the
* number of rendered frames multiplied by the fixed time increment per
* frame
*/
std::chrono::steady_clock::time_point currentPlaybackInterpolationTime() const;
/**
* Returns the simulated application time. This simulated application time is only
* used when playback is set to be in the mode where a screenshot is captured with
* every rendered frame (enableTakeScreenShotDuringPlayback() is used to enable this
* mode). At the start of playback, this timer is set to the value of the current
* applicationTime function provided by the window delegate (used during normal
* mode or playback). However, during playback it is incremented by the fixed
* framerate of the playback rather than the actual clock value.
*
* \returns application time in seconds, for use in playback-with-frames mode
*/
double currentApplicationInterpolationTime() const;
/**
* Starts a recording session, which will save data to the provided filename
* according to the data format specified, and will continue until recording is
* stopped using stopRecording() method.
*
* \param filename file saved with recorded keyframes.
*
* \returns true if recording to file starts without errors.
*/
bool startRecording(const std::string& filename);
/**
* Starts a recording session, which will save data to the provided filename
* in ASCII data format until recording is stopped using stopRecording() method.
*
* \param dataMode The format in which the session recording is stored
*/
void setRecordDataFormat(DataMode dataMode);
/**
* Used to stop a recording in progress. If open, the recording file will be closed,
* and all keyframes deleted from memory.
*/
void stopRecording();
/**
* Used to check if a session recording is in progress.
*
* \return true if recording is in progress
*/
bool isRecording() const;
/**
* Starts a playback session, which can run in one of three different time modes.
*
* \param filename file containing recorded keyframes to play back. The file path
* is relative to the base recordings directory specified in the
* config file by the RECORDINGS variable
* \param timeMode which of the 3 time modes to use for time reference during
* \param forceSimTimeAtStart if true simulation time is forced to that of playback
* playback: recorded time, application time, or simulation time. See the
* LuaLibrary entry for SessionRecording for details on these time modes
* \param loop if true then the file will playback in loop mode, continuously
* looping back to the beginning until it is manually stopped
* \param shouldWaitForFinishedTiles if true, the playback will wait for tiles to be
* finished before progressing to the next frame. This value is only used when
* `enableTakeScreenShotDuringPlayback` was called before. Otherwise this value
* will be ignored
*
* \return `true` if recording to file starts without errors
*/
bool startPlayback(std::string& filename, KeyframeTimeRef timeMode,
bool forceSimTimeAtStart, bool loop, bool shouldWaitForFinishedTiles);
/**
* Used to stop a playback in progress. If open, the playback file will be closed,
* and all keyframes deleted from memory.
*/
void stopPlayback();
/**
* Returns playback pause status.
*
* \return `true` if playback is paused
*/
bool isPlaybackPaused();
/**
* Pauses a playback session. This does both the normal pause functionality of
* setting simulation delta time to zero, and pausing the progression through the
* timeline.
*
* \param pause if true, then will set playback timeline progression to zero
*/
void setPlaybackPause(bool pause);
/**
* Enables that rendered frames should be saved during playback
* \param fps Number of frames per second.
*/
void enableTakeScreenShotDuringPlayback(int fps);
/**
* Used to disable that renderings are saved during playback
*/
void disableTakeScreenShotDuringPlayback();
/**
* Used to check if a session playback is in progress.
* \returns true if playback is in progress.
*/
bool isPlayingBack() const;
/**
* Is saving frames during playback
*/
bool isSavingFramesDuringPlayback() const;
bool shouldWaitForTileLoading() const;
/**
* Used to obtain the state of idle/recording/playback.
*
* \return int value of state as defined by struct SessionState
*/
SessionState state() const;
/**
* Used to trigger a save of the camera states (position, rotation, focus node,
* whether it is following the rotation of a node, and timestamp). The data will be
* saved to the recording file only if a recording is currently in progress.
*/
void saveCameraKeyframeToTimeline();
/**
* Used to trigger a save of the current timing states. The data will be saved to the
* recording file only if a recording is currently in progress.
*/
void saveTimeKeyframeToTimeline();
/**
* Used to trigger a save of a script to the recording file, but only if a recording
* is currently in progress.
*
* \param scriptToSave String of the Lua command to be saved
*/
void saveScriptKeyframeToTimeline(std::string scriptToSave);
/**
* \return The Lua library that contains all Lua functions available to affect the
* interaction
*/
static openspace::scripting::LuaLibrary luaLibrary();
/**
* Used to request a callback for notification of playback state change.
*
* \param cb function handle for callback
*
* \return CallbackHandle value of callback number
*/
CallbackHandle addStateChangeCallback(StateChangeCallback cb);
/**
* Removes the callback for notification of playback state change.
*
* \param callback function handle for the callback
*/
void removeStateChangeCallback(CallbackHandle callback);
/**
* Provides list of available playback files.
*
* \return vector of filenames in recordings dir
*/
std::vector<std::string> playbackList() const;
/**
* Reads a camera keyframe from a binary format playback file, and populates input
* references with the parameters of the keyframe.
*
* \param times reference to a timestamps structure which contains recorded times
* \param kf reference to a camera keyframe which contains camera details
* \param file an ifstream reference to the playback file being read
* \param lineN keyframe number in playback file where this keyframe resides
*
* \return true if data read has no errors
*/
bool readCameraKeyframeBinary(Timestamps& times,
datamessagestructures::CameraKeyframe& kf, std::ifstream& file, int lineN);
/**
* Reads a camera keyframe from an ascii format playback file, and populates input
* references with the parameters of the keyframe.
*
* \param times reference to a timestamps structure which contains recorded times
* \param kf reference to a camera keyframe which contains camera details
* \param currentParsingLine string containing the most current line that was read
* \param lineN line number in playback file where this keyframe resides
*
* \return true if data read has no errors
*/
bool readCameraKeyframeAscii(Timestamps& times,
datamessagestructures::CameraKeyframe& kf, std::string currentParsingLine,
int lineN);
/**
* Reads a time keyframe from a binary format playback file, and populates input
* references with the parameters of the keyframe.
*
* \param times reference to a timestamps structure which contains recorded times
* \param kf reference to a time keyframe which contains time details
* \param file an ifstream reference to the playback file being read
* \param lineN keyframe number in playback file where this keyframe resides
*
* \return true if data read has no errors
*/
bool readTimeKeyframeBinary(Timestamps& times,
datamessagestructures::TimeKeyframe& kf, std::ifstream& file, int lineN);
/**
* Reads a time keyframe from an ascii format playback file, and populates input
* references with the parameters of the keyframe.
*
* \param times reference to a timestamps structure which contains recorded times
* \param kf reference to a time keyframe which contains time details
* \param currentParsingLine string containing the most current line that was read
* \param lineN line number in playback file where this keyframe resides
*
* \return true if data read has no errors
*/
bool readTimeKeyframeAscii(Timestamps& times,
datamessagestructures::TimeKeyframe& kf, std::string currentParsingLine,
int lineN);
/**
* Reads a script keyframe from a binary format playback file, and populates input
* references with the parameters of the keyframe.
*
* \param times reference to a timestamps structure which contains recorded times
* \param kf reference to a script keyframe which contains the size of the script
* (in chars) and the text itself
* \param file an ifstream reference to the playback file being read
* \param lineN keyframe number in playback file where this keyframe resides
*
* \return true if data read has no errors
*/
bool readScriptKeyframeBinary(Timestamps& times,
datamessagestructures::ScriptMessage& kf, std::ifstream& file, int lineN);
/**
* Reads a script keyframe from an ascii format playback file, and populates input
* references with the parameters of the keyframe.
*
* \param times reference to a timestamps structure which contains recorded times
* \param kf reference to a script keyframe which contains the size of the script
* (in chars) and the text itself
* \param currentParsingLine string containing the most current line that was read
* \param lineN line number in playback file where this keyframe resides
*
* \return true if data read has no errors
*/
bool readScriptKeyframeAscii(Timestamps& times,
datamessagestructures::ScriptMessage& kf, std::string currentParsingLine,
int lineN);
/**
* Writes a camera keyframe to a binary format recording file using a CameraKeyframe
*
* \param times reference to a timestamps structure which contains recorded times
* \param kf reference to a camera keyframe which contains the camera details
* \param kfBuffer a buffer temporarily used for preparing data to be written
* \param file an ofstream reference to the recording file being written-to
*/
void saveCameraKeyframeBinary(Timestamps& times,
datamessagestructures::CameraKeyframe& kf, unsigned char* kfBuffer,
std::ofstream& file);
/**
* Writes a camera keyframe to an ascii format recording file using a CameraKeyframe
*
* \param times reference to a timestamps structure which contains recorded times
* \param kf reference to a camera keyframe which contains the camera details
* \param file an ofstream reference to the recording file being written-to
*/
void saveCameraKeyframeAscii(Timestamps& times,
datamessagestructures::CameraKeyframe& kf, std::ofstream& file);
/**
* Writes a time keyframe to a binary format recording file using a TimeKeyframe
*
* \param times reference to a timestamps structure which contains recorded times
* \param kf reference to a time keyframe which contains the time details
* \param kfBuffer a buffer temporarily used for preparing data to be written
* \param file an ofstream reference to the recording file being written-to
*/
void saveTimeKeyframeBinary(Timestamps& times,
datamessagestructures::TimeKeyframe& kf, unsigned char* kfBuffer,
std::ofstream& file);
/**
* Writes a time keyframe to an ascii format recording file using a TimeKeyframe
*
* \param times reference to a timestamps structure which contains recorded times
* \param kf reference to a time keyframe which contains the time details
* \param file an ofstream reference to the recording file being written-to
*/
void saveTimeKeyframeAscii(Timestamps& times,
datamessagestructures::TimeKeyframe& kf, std::ofstream& file);
/**
* Writes a script keyframe to a binary format recording file using a ScriptMessage
*
* \param times reference to a timestamps structure which contains recorded times
* \param sm reference to a ScriptMessage object which contains the script details
* \param smBuffer a buffer temporarily used for preparing data to be written
* \param file an ofstream reference to the recording file being written-to
*/
void saveScriptKeyframeBinary(Timestamps& times,
datamessagestructures::ScriptMessage& sm, unsigned char* smBuffer,
std::ofstream& file);
/**
* Writes a script keyframe to an ascii format recording file using a ScriptMessage
*
* \param times reference to a timestamps structure which contains recorded times
* \param sm reference to a ScriptMessage which contains the script details
* \param file an ofstream reference to the recording file being written-to
*/
void saveScriptKeyframeAscii(Timestamps& times,
datamessagestructures::ScriptMessage& sm, std::ofstream& file);
/**
* Since session recordings only record changes, the initial conditions aren't
* preserved when a playback starts. This function is called whenever a property
* value is set and a recording is in progress. Before the set happens, this
* function will read the current value of the property and store it so that when
* the recording is finished, the initial state will be added as a set property
* command at the beginning of the recording file, to be applied when playback
* starts.
*
* \param prop The property being set
*/
void savePropertyBaseline(properties::Property& prop);
/**
* Reads header information from a session recording file
*
* \param stream reference to ifstream that contains the session recording file data
* \param readLen_chars number of characters to be read, which may be the expected
* length of the header line, or an arbitrary number of characters within it
*/
static std::string readHeaderElement(std::ifstream& stream, size_t readLen_chars);
/**
* Reads header information from a session recording file
*
* \param stream reference to ifstream that contains the session recording file
* data
* \param readLen_chars number of characters to be read, which may be the expected
* length of the header line, or an arbitrary number of characters within it
*/
static std::string readHeaderElement(std::stringstream& stream, size_t readLen_chars);
/**
* Writes a header to a binary recording file buffer
*
* \param times reference to a timestamps structure which contains recorded times
* \param type single character signifying the keyframe type
* \param kfBuffer the char buffer holding the recording info to be written
* \param idx index into write buffer (this is updated with the num of chars written)
*/
static void saveHeaderBinary(Timestamps& times, char type, unsigned char* kfBuffer,
size_t& idx);
/**
* Writes a header to an ascii recording file buffer
*
* \param times reference to a timestamps structure which contains recorded times
* \param type string signifying the keyframe type
* \param line the stringstream buffer being written to
*/
static void saveHeaderAscii(Timestamps& times, const std::string& type,
std::stringstream& line);
/**
* Saves a keyframe to an ascii recording file
*
* \param entry the ascii string version of the keyframe (any type)
* \param file ofstream object to write to
*/
static void saveKeyframeToFile(std::string entry, std::ofstream& file);
/**
* Checks if a specified recording file ends with a particular file extension
*
* \param filename the name of the file to record to
* \param extension the file extension to check for
*/
static bool hasFileExtension(std::string filename, std::string extension);
/**
* Converts file format of a session recording file to the current format version
* (will determine the file format conversion to convert from based on the file's
* header version number).
*
* \param filename name of the file to convert
* \param depth iteration number to prevent runaway recursion (init call with zero)
*
* \return string containing the filename of the previous conversion step. This is
* used if there are multiple conversion steps where each step has to use
* the output of the previous.
*/
std::string convertFile(std::string filename, int depth = 0);
/**
* Converts file format of a session recording file to the current format version
* (will determine the file format conversion to convert from based on the file's
* header version number). Accepts a relative path (currently from task runner dir)
* rather than a path assumed to be relative to ${RECORDINGS}.
*
* \param filenameRelative name of the file to convert
*/
void convertFileRelativePath(std::string filenameRelative);
/**
* Goes to legacy session recording inherited class, and calls its convertFile()
* method, and then returns the resulting conversion filename.
*
* \param filename name of the file to convert
* \param depth iteration number to prevent runaway recursion (init call with zero)
*
* \return string containing the filename of the conversion
*/
virtual std::string getLegacyConversionResult(std::string filename, int depth);
/*
* Version string for file format version currently supported by this class
*
* \return string of the file format version this class supports
*/
virtual std::string fileFormatVersion();
/*
* Version string for file format version that a conversion operation will convert
* to (e.g. upgrades to this version). This is only relevant for inherited classes
* that support conversion from legacy versions (if called in the base class, it
* will return its own current version).
*
* \return string of the file format version this class supports
*/
virtual std::string targetFileFormatVersion();
/*
* Determines a filename for the conversion result based on the original filename
* and the file format version number.
*
* \param filename source filename to be converted
*
* \return pathname of the converted version of the file
*/
std::string determineConversionOutFilename(const std::string filename, DataMode mode);
protected:
properties::BoolProperty _renderPlaybackInformation;
properties::BoolProperty _ignoreRecordedScale;
enum class RecordedType {
Camera = 0,
Time,
Script,
Invalid
};
struct TimelineEntry {
RecordedType keyframeType;
unsigned int idxIntoKeyframeTypeArray;
Timestamps t3stamps;
};
double _timestampRecordStarted = 0.0;
Timestamps _timestamps3RecordStarted{ 0.0, 0.0, 0.0 };
double _timestampPlaybackStarted_application = 0.0;
double _timestampPlaybackStarted_simulation = 0.0;
double _timestampApplicationStarted_simulation = 0.0;
bool hasCameraChangedFromPrev(datamessagestructures::CameraKeyframe kfNew);
double appropriateTimestamp(Timestamps t3stamps);
double equivalentSimulationTime(double timeOs, double timeRec, double timeSim);
double equivalentApplicationTime(double timeOs, double timeRec, double timeSim);
void recordCurrentTimePauseState();
void recordCurrentTimeRate();
bool handleRecordingFile(std::string filenameIn);
static bool isPath(std::string& filename);
void removeTrailingPathSlashes(std::string& filename);
bool playbackCamera();
bool playbackTimeChange();
bool playbackScript();
bool playbackAddEntriesToTimeline();
void signalPlaybackFinishedForComponent(RecordedType type);
void handlePlaybackEnd();
bool findFirstCameraKeyframeInTimeline();
Timestamps generateCurrentTimestamp3(double keyframeTime);
static void saveStringToFile(const std::string& s, unsigned char* kfBuffer,
size_t& idx, std::ofstream& file);
static void saveKeyframeToFileBinary(unsigned char* bufferSource, size_t size,
std::ofstream& file);
bool addKeyframe(Timestamps t3stamps,
interaction::KeyframeNavigator::CameraPose keyframe, int lineNum);
bool addKeyframe(Timestamps t3stamps,
datamessagestructures::TimeKeyframe keyframe, int lineNum);
bool addKeyframe(Timestamps t3stamps,
std::string scriptToQueue, int lineNum);
bool addKeyframeToTimeline(std::vector<TimelineEntry>& timeline, RecordedType type,
size_t indexIntoTypeKeyframes, Timestamps t3stamps, int lineNum);
void initializePlayback_time(double now);
void initializePlayback_modeFlags();
bool initializePlayback_timeline();
void initializePlayback_triggerStart();
void moveAheadInTime();
void lookForNonCameraKeyframesThatHaveComeDue(double currTime);
void updateCameraWithOrWithoutNewKeyframes(double currTime);
bool isTimeToHandleNextNonCameraKeyframe(double currTime);
bool processNextNonCameraKeyframeAheadInTime();
bool findNextFutureCameraIndex(double currTime);
bool processCameraKeyframe(double now);
bool processScriptKeyframe();
bool readSingleKeyframeCamera(datamessagestructures::CameraKeyframe& kf,
Timestamps& times, DataMode mode, std::ifstream& file,
std::string& inLine, const int lineNum);
void saveSingleKeyframeCamera(datamessagestructures::CameraKeyframe& kf,
Timestamps& times, DataMode mode, std::ofstream& file, unsigned char* buffer);
bool readSingleKeyframeTime(datamessagestructures::TimeKeyframe& kf,
Timestamps& times, DataMode mode, std::ifstream& file, std::string& inLine,
const int lineNum);
void saveSingleKeyframeTime(datamessagestructures::TimeKeyframe& kf,
Timestamps& times, DataMode mode, std::ofstream& file, unsigned char* buffer);
bool readSingleKeyframeScript(datamessagestructures::ScriptMessage& kf,
Timestamps& times, DataMode mode, std::ifstream& file, std::string& inLine,
const int lineNum);
void saveSingleKeyframeScript(datamessagestructures::ScriptMessage& kf,
Timestamps& times, DataMode mode, std::ofstream& file, unsigned char* buffer);
void saveScriptKeyframeToPropertiesBaseline(std::string script);
bool isPropertyAllowedForBaseline(const std::string& propString);
unsigned int findIndexOfLastCameraKeyframeInTimeline();
bool doesTimelineEntryContainCamera(unsigned int index) const;
bool doesStartWithSubstring(const std::string& s, const std::string& matchSubstr);
void trimCommandsFromScriptIfFound(std::string& script);
void replaceCommandsFromScriptIfFound(std::string& script);
RecordedType getNextKeyframeType();
RecordedType getPrevKeyframeType();
double getNextTimestamp();
double getPrevTimestamp();
void cleanUpPlayback();
void cleanUpRecording();
void cleanUpTimelinesAndKeyframes();
bool convertEntries(std::string& inFilename, std::stringstream& inStream,
DataMode mode, int lineNum, std::ofstream& outFile);
virtual bool convertCamera(std::stringstream& inStream, DataMode mode, int lineNum,
std::string& inputLine, std::ofstream& outFile, unsigned char* buff);
virtual bool convertTimeChange(std::stringstream& inStream, DataMode mode,
int lineNum, std::string& inputLine, std::ofstream& outFile, unsigned char* buff);
virtual bool convertScript(std::stringstream& inStream, DataMode mode, int lineNum,
std::string& inputLine, std::ofstream& outFile, unsigned char* buff);
DataMode readModeFromHeader(std::string filename);
void readPlaybackHeader_stream(std::stringstream& conversionInStream,
std::string& version, DataMode& mode);
void populateListofLoadedSceneGraphNodes();
void checkIfScriptUsesScenegraphNode(std::string s);
bool checkForScenegraphNodeAccessScene(std::string& s);
bool checkForScenegraphNodeAccessNav(std::string& navTerm);
std::string extractScenegraphNodeFromScene(std::string& s);
bool checkIfInitialFocusNodeIsLoaded(unsigned int firstCamIndex);
std::string isolateTermFromQuotes(std::string s);
void eraseSpacesFromString(std::string& s);
std::string getNameFromSurroundingQuotes(std::string& s);
static void writeToFileBuffer(unsigned char* buf, size_t& idx, double src);
static void writeToFileBuffer(unsigned char* buf, size_t& idx, std::vector<char>& cv);
static void writeToFileBuffer(unsigned char* buf, size_t& idx, unsigned char c);
static void writeToFileBuffer(unsigned char* buf, size_t& idx, bool b);
void readFileIntoStringStream(std::string filename,
std::ifstream& inputFstream, std::stringstream& stream);
DataMode _recordingDataMode = DataMode::Binary;
SessionState _state = SessionState::Idle;
SessionState _lastState = SessionState::Idle;
std::string _playbackFilename;
std::ifstream _playbackFile;
std::string _playbackLineParsing;
std::ofstream _recordFile;
int _playbackLineNum = 1;
int _recordingEntryNum = 1;
KeyframeTimeRef _playbackTimeReferenceMode;
datamessagestructures::CameraKeyframe _prevRecordedCameraKeyframe;
bool _playbackActive_camera = false;
bool _playbackActive_time = false;
bool _playbackActive_script = false;
bool _hasHitEndOfCameraKeyframes = false;
bool _playbackPausedWithinDeltaTimePause = false;
bool _playbackLoopMode = false;
bool _playbackForceSimTimeAtStart = false;
double _playbackPauseOffset = 0.0;
double _previousTime = 0.0;
bool _saveRenderingDuringPlayback = false;
double _saveRenderingDeltaTime = 1.0 / 30.0;
double _saveRenderingCurrentRecordedTime = 0.0;
bool _shouldWaitForFinishLoadingWhenPlayback = false;
std::chrono::steady_clock::duration _saveRenderingDeltaTime_interpolation_usec;
std::chrono::steady_clock::time_point _saveRenderingCurrentRecordedTime_interpolation;
double _saveRenderingCurrentApplicationTime_interpolation = 0.0;
long long _saveRenderingClockInterpolation_countsPerSec = 1;
bool _saveRendering_isFirstFrame = true;
unsigned char _keyframeBuffer[_saveBufferMaxSize_bytes];
bool _cleanupNeededRecording = false;
bool _cleanupNeededPlayback = false;
const std::string scriptReturnPrefix = "return ";
std::vector<interaction::KeyframeNavigator::CameraPose> _keyframesCamera;
std::vector<datamessagestructures::TimeKeyframe> _keyframesTime;
std::vector<std::string> _keyframesScript;
std::vector<TimelineEntry> _timeline;
std::vector<std::string> _keyframesSavePropertiesBaseline_scripts;
std::vector<TimelineEntry> _keyframesSavePropertiesBaseline_timeline;
std::vector<std::string> _propertyBaselinesSaved;
const std::vector<std::string> _propertyBaselineRejects = {
"NavigationHandler.OrbitalNavigator.Anchor",
"NavigationHandler.OrbitalNavigator.Aim",
"NavigationHandler.OrbitalNavigator.RetargetAnchor",
"NavigationHandler.OrbitalNavigator.RetargetAim"
};
//A script that begins with an exact match of any of the strings contained in
// _scriptRejects will not be recorded
const std::vector<std::string> _scriptRejects = {
"openspace.sessionRecording.enableTakeScreenShotDuringPlayback",
"openspace.sessionRecording.startPlayback",
"openspace.sessionRecording.stopPlayback",
"openspace.sessionRecording.startRecording",
"openspace.sessionRecording.stopRecording",
"openspace.scriptScheduler.clear"
};
const std::vector<std::string> _navScriptsUsingNodes = {
"RetargetAnchor",
"Anchor",
"Aim"
};
//Any script snippet included in this vector will be trimmed from any script
// from the script manager, before it is recorded in the session recording file.
// The remainder of the script will be retained.
const std::vector<std::string> _scriptsToBeTrimmed = {
"openspace.sessionRecording.togglePlaybackPause"
};
//Any script snippet included in this vector will be trimmed from any script
// from the script manager, before it is recorded in the session recording file.
// The remainder of the script will be retained.
const std::vector<ScriptSubstringReplace> _scriptsToBeReplaced = {
{
"openspace.time.pauseToggleViaKeyboard",
"openspace.time.interpolateTogglePause"
}
};
std::vector<std::string> _loadedNodes;
unsigned int _idxTimeline_nonCamera = 0;
unsigned int _idxTime = 0;
unsigned int _idxScript = 0;
unsigned int _idxTimeline_cameraPtrNext = 0;
unsigned int _idxTimeline_cameraPtrPrev = 0;
unsigned int _idxTimeline_cameraFirstInTimeline = 0;
double _cameraFirstInTimeline_timestamp = 0;
int _nextCallbackHandle = 0;
std::vector<std::pair<CallbackHandle, StateChangeCallback>> _stateChangeCallbacks;
DataMode _conversionDataMode = DataMode::Binary;
int _conversionLineNum = 1;
const int _maximumRecursionDepth = 50;
};
// Instructions for bumping the file format version with new changes:
//
// 1. Create a new subclass with the current version # in its name, such as:
// SessionRecording_legacy_####, which inherits from SessionRecording
// 2. Override any method that changes in the new version. This includes both
// methods in SessionRecording class and structs in
// openspace::datamessagestructure that do data read/writes. Make the modified
// method/struct virtual, and override it in the new legacy subclass. This
// override will contain the code as it is before the new changes. This will
// need to be done in every legacy subclass/struct that exists, but only if that
// subclass does NOT already contain an override of that method/struct.
// 3. Override FileHeaderVersion with the version # of the new subclass (which is
// the version being replaced by the new changes).
// 4. Override TargetConvertVersion with the version # with the new changes. This
// is now the version that this legacy subclass converts up to.
// 5. Override getLegacyConversionResult method so that it creates an instance of
// the new version subclass. This is how the current version looks back to the
// legacy version that preceded it.
// 6. The convert method for frame types that changed will need to be changed
// (for example SessionRecording_legacy_0085::convertScript uses its own
// override of script keyframe for the conversion functionality).
class SessionRecording_legacy_0085 : public SessionRecording {
public:
SessionRecording_legacy_0085() : SessionRecording() {}
~SessionRecording_legacy_0085() override {}
char FileHeaderVersion[FileHeaderVersionLength+1] = "00.85";
char TargetConvertVersion[FileHeaderVersionLength+1] = "01.00";
std::string fileFormatVersion() override {
return std::string(FileHeaderVersion);
}
std::string targetFileFormatVersion() override {
return std::string(TargetConvertVersion);
}
std::string getLegacyConversionResult(std::string filename, int depth) override;
struct ScriptMessage_legacy_0085 : public datamessagestructures::ScriptMessage {
void read(std::istream* in) override {
size_t strLen;
//Read string length from file
in->read(reinterpret_cast<char*>(&strLen), sizeof(strLen));
if (strLen > saveBufferStringSize_max) {
throw ConversionError("Invalid script size for conversion read");
auto operator<=>(const SessionRecording&) const = default;
std::vector<Entry> entries;
bool hasCameraFrame() const noexcept;
// Call the provided \p function for all entries of the specified type \tparam T. The
// function calls will be ordered by the entries timestamps. If the callback function
// returns `true`, the loop is aborted
template <typename T>
void forAll(std::function<bool (const T&)> function) {
for (const Entry& e : entries) {
if (std::holds_alternative<T>(e.value)) {
bool cont = function(std::get<T>(e.value));
if (cont) {
break;
}
}
//Read back full string
std::vector<char> temp(strLen + 1);
in->read(temp.data(), strLen);
temp[strLen] = '\0';
_script.erase();
_script = temp.data();
}
};
protected:
bool convertScript(std::stringstream& inStream, DataMode mode, int lineNum,
std::string& inputLine, std::ofstream& outFile, unsigned char* buffer) override;
}
};
} // namespace openspace
SessionRecording loadSessionRecording(const std::filesystem::path& filename);
void saveSessionRecording(const std::filesystem::path& filename,
const SessionRecording& sessionRecording, DataMode dataMode);
#include "sessionrecording.inl"
std::vector<ghoul::Dictionary> sessionRecordingToDictionary(
const SessionRecording& recording);
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___SESSIONRECORDING___H__

View File

@@ -0,0 +1,288 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2025 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___SESSIONRECORDINGHANDLER___H__
#define __OPENSPACE_CORE___SESSIONRECORDINGHANDLER___H__
#include <openspace/properties/propertyowner.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/scripting/lualibrary.h>
namespace openspace::interaction {
class SessionRecordingHandler : public properties::PropertyOwner {
public:
enum class SessionState {
Idle = 0,
Recording,
Playback,
PlaybackPaused
};
using CallbackHandle = int;
using StateChangeCallback = std::function<void()>;
SessionRecordingHandler();
~SessionRecordingHandler() override = default;
/**
* This is called with every rendered frame. If in recording state, the camera state
* will be saved to the recording file (if its state has changed since last). If in
* playback state, the next keyframe will be used (if it is time to do so).
*/
void preSynchronization(double dt);
/**
* If enabled, calling this function will render information about the session
* recording that is currently taking place to the screen.
*/
void render() const;
/**
* Fixed delta time set by user for use during saving of frame during playback mode.
*/
double fixedDeltaTimeDuringFrameOutput() const;
/**
* Returns the number of microseconds that have elapsed since playback started, if
* playback is set to be in the mode where a screenshot is captured with every
* rendered frame (enableTakeScreenShotDuringPlayback() is used to enable this mode).
* At the start of playback, this timer is set to the current steady_clock value.
* However, during playback it is incremented by the fixed framerate of the playback
* rather than the actual clock value (as in normal operation).
*
* \return Number of microseconds elapsed since playback started in terms of the
* number of rendered frames multiplied by the fixed time increment per frame
*/
std::chrono::steady_clock::time_point currentPlaybackInterpolationTime() const;
/**
* Returns the simulated application time. This simulated application time is only
* used when playback is set to be in the mode where a screenshot is captured with
* every rendered frame (enableTakeScreenShotDuringPlayback() is used to enable this
* mode). At the start of playback, this timer is set to the value of the current
* applicationTime function provided by the window delegate (used during normal mode
* or playback). However, during playback it is incremented by the fixed framerate of
* the playback rather than the actual clock value.
*
* \return Application time in seconds, for use in playback-with-frames mode
*/
double currentApplicationInterpolationTime() const;
/**
* Starts a recording session, which will save data to the provided filename according
* to the data format specified, and will continue until recording is stopped using
* stopRecording() method.
*
* \return `true` if recording to file starts without errors
*/
void startRecording();
/**
* Used to stop a recording in progress. If open, the recording file will be closed,
* and all keyframes deleted from memory.
* \param filename File saved with recorded keyframes
*/
void stopRecording(const std::filesystem::path& filename, DataMode dataMode);
/**
* Used to check if a session recording is in progress.
*
* \return `true` if recording is in progress
*/
bool isRecording() const;
/**
* Starts a playback session, which can run in one of three different time modes.
*
* \param filename File containing recorded keyframes to play back. The file path is
* relative to the base recordings directory specified in the config
* file by the RECORDINGS variable
* \param timeMode Which of the 3 time modes to use for time reference during
* \param loop If true then the file will playback in loop mode, continuously looping
* back to the beginning until it is manually stopped
* \param shouldWaitForFinishedTiles If true, the playback will wait for tiles to be
* finished before progressing to the next frame. This value is only used when
* `enableTakeScreenShotDuringPlayback` was called before. Otherwise this value
* will be ignored
*/
void startPlayback(SessionRecording timeline, bool loop,
bool shouldWaitForFinishedTiles, std::optional<int> saveScreenshotFps);
/**
* Used to stop a playback in progress. If open, the playback file will be closed, and
* all keyframes deleted from memory.
*/
void stopPlayback();
/**
* Returns playback pause status.
*
* \return `true` if playback is paused
*/
bool isPlaybackPaused() const;
/**
* Pauses a playback session. This does both the normal pause functionality of setting
* simulation delta time to zero, and pausing the progression through the timeline.
*
* \param pause If `true`, then will set playback timeline progression to zero
*/
void setPlaybackPause(bool pause);
/**
* Enables that rendered frames should be saved during playback.
*
* \param fps Number of frames per second.
*/
//void enableTakeScreenShotDuringPlayback(int fps);
/**
* Used to disable that renderings are saved during playback.
*/
//void disableTakeScreenShotDuringPlayback();
/**
* Used to check if a session playback is in progress.
*
* \return `true` if playback is in progress
*/
bool isPlayingBack() const;
void seek(double recordingTime);
/**
* Is saving frames during playback.
*/
bool isSavingFramesDuringPlayback() const;
bool shouldWaitForTileLoading() const;
/**
* Used to obtain the state of idle/recording/playback.
*
* \return int value of state as defined by struct SessionState
*/
SessionState state() const;
/**
* Used to trigger a save of a script to the recording file, but only if a recording
* is currently in progress.
*
* \param script String of the Lua command to be saved
*/
void saveScriptKeyframeToTimeline(std::string script);
/**
* \return The Lua library that contains all Lua functions available to affect the
* interaction
*/
static openspace::scripting::LuaLibrary luaLibrary();
/**
* Used to request a callback for notification of playback state change.
*
* \param cb Function handle for callback
* \return CallbackHandle value of callback number
*/
CallbackHandle addStateChangeCallback(StateChangeCallback cb);
/**
* Removes the callback for notification of playback state change.
*
* \param callback Function handle for the callback
*/
void removeStateChangeCallback(CallbackHandle handle);
/**
* Provides list of available playback files.
*
* \return Vector of filenames in recordings dir
*/
std::vector<std::string> playbackList() const;
/**
* Since session recordings only record changes, the initial conditions aren't
* preserved when a playback starts. This function is called whenever a property value
* is set and a recording is in progress. Before the set happens, this function will
* read the current value of the property and store it so that when the recording is
* finished, the initial state will be added as a set property command at the
* beginning of the recording file, to be applied when playback starts.
*
* \param prop The property being set
*/
void savePropertyBaseline(properties::Property& prop);
private:
void tickPlayback(double dt);
void tickRecording(double dt);
void setupPlayback(double startTime);
void cleanUpTimelinesAndKeyframes();
void checkIfScriptUsesScenegraphNode(std::string_view s) const;
properties::BoolProperty _renderPlaybackInformation;
properties::BoolProperty _ignoreRecordedScale;
properties::BoolProperty _addModelMatrixinAscii;
struct {
double elapsedTime = 0.0;
bool isLooping = false;
bool playbackPausedWithDeltaTimePause = false;
bool waitForLoading = false;
struct {
bool enabled = false;
double deltaTime = 1.0 / 30.0;
std::chrono::steady_clock::time_point currentRecordedTime;
double currentApplicationTime = 0.0;
} saveScreenshots;
} _playback;
struct {
double elapsedTime = 0.0;
} _recording;
SessionState _state = SessionState::Idle;
SessionState _lastState = SessionState::Idle;
SessionRecording _timeline;
std::vector<SessionRecording::Entry>::const_iterator _currentEntry =
_timeline.entries.end();
std::unordered_map<std::string, std::string> _savePropertiesBaseline;
std::vector<std::string> _loadedNodes;
int _nextCallbackHandle = 0;
std::vector<std::pair<CallbackHandle, StateChangeCallback>> _stateChangeCallbacks;
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___SESSIONRECORDINGHANDLER___H__

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -26,7 +26,7 @@
#define __OPENSPACE_CORE___CONVERTRECFORMATTASK___H__
#include <openspace/util/task.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/interaction/sessionrecordinghandler.h>
#include <ghoul/glm.h>
#include <filesystem>
@@ -41,26 +41,15 @@ public:
ToBinary
};
ConvertRecFormatTask(const ghoul::Dictionary& dictionary);
~ConvertRecFormatTask() override;
~ConvertRecFormatTask() override = default;
std::string description() override;
void perform(const Task::ProgressCallback& progressCallback) override;
static documentation::Documentation documentation();
void convert();
private:
void convertToAscii();
void convertToBinary();
void determineFormatType();
std::string addFileSuffix(const std::string& filePath, const std::string& suffix);
std::filesystem::path _inFilePath;
std::filesystem::path _outFilePath;
std::ifstream _iFile;
std::ofstream _oFile;
SessionRecording::DataMode _fileFormatType;
std::string _version;
std::string _valueFunctionLua;
SessionRecording* sessRec;
DataMode _dataMode;
};
} // namespace openspace::interaction

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -37,7 +37,7 @@ namespace openspace::interaction {
/**
* Actions that any button of a websocket can have. Each button must be in one of these
* states
* states.
*/
enum class WebsocketAction : uint8_t {
/// Idle state if the button is unpressed and has been unpressed since last frame

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -51,8 +51,8 @@ struct Milestone {
* phases within phases. Designed for WORM usage (Write Once, Read Multiple), and,
* therefore, has only accessors.
*
* Each MissionPhase is characterized by its MissionPhase::name, a TimeRange, an
* optional MissionPhase::description, and optional subphases.
* Each MissionPhase is characterized by its MissionPhase::name, a TimeRange, an optional
* MissionPhase::description, and optional subphases.
*/
class MissionPhase {
public:
@@ -147,6 +147,7 @@ public:
/**
* Returns the Documentation that describes the ghoul::Dictionarty that this
* MissionPhase can be constructed from.
*
* \return The Documentation that describes the required structure for a Dictionary
*/
static documentation::Documentation Documentation();
@@ -161,7 +162,7 @@ protected:
* \param trace The list of MissionPhase%s that are active during the time \p time
* \param maxDepth The maximum depth of levels that will be considered
*
* \pre maxDepth must not be negative
* \pre \p maxDepth must not be negative
*/
void phaseTrace(double time, Trace& trace, int maxDepth) const;

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -48,15 +48,11 @@ public:
MissionManager();
/**
* Reads a mission from file and maps the mission name to the Mission object. If
* this is the first mission to be loaded, the mission will also be set as the
* current active mission.
* Loads the provided mission. If this is the first mission to be loaded, the mission
* will also be set as the current active mission.
*
* \param filename The file that contains the mission that is to be loaded
* \param mission The file that contains the mission that is to be loaded
* \return The name of the mission that was loaded
* \pre \p filename must not be empty
* \pre \p filename must not contain tokens
* \pre \p filename must exist
*/
std::string loadMission(Mission mission);
@@ -64,7 +60,7 @@ public:
* Unloads a previously loaded mission identified by the provided \p missionName.
*
* \param missionName The name of the mission that should be unloded
* \pre \p filename must not be empty
*
* \pre \p missionName must be a valid mission that has previously been loaded
*/
void unloadMission(const std::string& missionName);
@@ -82,18 +78,18 @@ public:
* Sets the mission with the name \p missionName as the current mission. The current
* mission is what is return by `currentMission()`.
*
* \pre missionName must not be empty
* \pre \p missionName must not be empty
*/
void setCurrentMission(const std::string& missionName);
/**
* Returns true if a current mission exists
* Returns true if a current mission exists.
*/
bool hasCurrentMission() const;
/**
* Returns the latest mission specified to `setCurrentMission()`. If no mission has
* been specified, the first mission loaded will be returned. If no mission has been
* Returns the latest mission specified to #setCurrentMission. If no mission has been
* specified, the first mission loaded will be returned. If no mission has been
* loaded, a warning will be printed and a dummy mission will be returned.
*/
const Mission& currentMission();
@@ -103,7 +99,6 @@ public:
*/
const std::map<std::string, Mission>& missionMap();
static scripting::LuaLibrary luaLibrary();
private:

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -57,19 +57,21 @@ public:
CameraPose() = default;
CameraPose(datamessagestructures::CameraKeyframe&& kf);
auto operator<=>(const CameraPose&) const = default;
};
/**
* Update camera position using the next camera pose keyframe from the timeline.
* Returns true if camera was set to a pose from the next keyframe.
* Returns false if no keyframes are available after the current time.
* \param camera A reference to the camera object to have its pose updated.
* \param ignoreFutureKeyframes true if only past keyframes are to be used.
* \returns true only if a new future keyframe is available to set camera pose.
*/
bool updateCamera(Camera& camera, bool ignoreFutureKeyframes);
static bool updateCamera(Camera* camera, const CameraPose prevPose,
const CameraPose nextPose, double t, bool ignoreFutureKeyframes);
* Update camera position using the next camera pose keyframe from the timeline.
* Returns true if camera was set to a pose from the next keyframe. Returns false if
* no keyframes are available after the current time.
*
* \param camera A reference to the camera object to have its pose updated
* \param ignoreFutureKeyframes `true` if only past keyframes are to be used
* \return true only if a new future keyframe is available to set camera pose
*/
void updateCamera(Camera& camera, bool ignoreFutureKeyframes);
static void updateCamera(Camera* camera, const CameraPose& prevPose,
const CameraPose& nextPose, double t, bool ignoreFutureKeyframes);
Timeline<CameraPose>& timeline();
void addKeyframe(double timestamp, KeyframeNavigator::CameraPose pose);

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -85,7 +85,9 @@ public:
OrbitalNavigator& orbitalNavigator();
KeyframeNavigator& keyframeNavigator();
PathNavigator& pathNavigator();
bool isKeyFrameInteractionEnabled() const;
float jumpToFadeDuration() const;
float interpolationTime() const;
// Callback functions
@@ -143,15 +145,15 @@ public:
NavigationState navigationState(const SceneGraphNode& referenceFrame) const;
void saveNavigationState(const std::filesystem::path& filepath,
const std::string& referenceFrameIdentifier);
const std::string& referenceFrameIdentifier) const;
void loadNavigationState(const std::string& filepath);
void loadNavigationState(const std::string& filepath, bool useTimeStamp);
/**
* Set camera state from a provided navigation state next frame. The actual position
* will computed from the scene in the same frame as it is set.
*
* \param state the navigation state to compute a camera positon from
* \param state The navigation state to compute a camera positon from
*/
void setNavigationStateNextFrame(const NavigationState& state);
@@ -161,14 +163,26 @@ public:
* node info. The actual position will computed from the scene in the same frame as
* it is set.
*
* \param spec the node specification from which to compute the resulting camera pose
* \param spec The node specification from which to compute the resulting camera pose
*/
void setCameraFromNodeSpecNextFrame(NodeCameraStateSpec spec);
/**
* \return The Lua library that contains all Lua functions available to affect the
* interaction
*/
* Trigger a transition script after first fading out the rendering, and fading in
* the rendering when the script is finished. One example use case could be to fade
* out, move the camera to another focus node, and then fade in
*
* \param transitionScript The Lua script to handle the transition. Can be anything
* \param fadeDuration An optional duration for the fading. If unspecified, use the
* JumpToFadeDuration property
*/
void triggerFadeToTransition(const std::string& transitionScript,
std::optional<float> fadeDuration = std::nullopt);
/**
* \return The Lua library that contains all Lua functions available to affect the
* interaction
*/
static scripting::LuaLibrary luaLibrary();
private:
@@ -181,9 +195,9 @@ private:
Camera* _camera = nullptr;
std::function<void()> _playbackEndCallback;
static constexpr double InteractionHystersis = 0.0125;
bool _inAnchorApproachSphere = false;
bool _inAnchorReachSphere = false;
const SceneGraphNode* _lastAnchor = nullptr;
OrbitalNavigator _orbitalNavigator;
KeyframeNavigator _keyframeNavigator;
@@ -195,6 +209,7 @@ private:
properties::BoolProperty _disableMouseInputs;
properties::BoolProperty _disableJoystickInputs;
properties::BoolProperty _useKeyFrameInteraction;
properties::FloatProperty _jumpToFadeDuration;
};
} // namespace openspace::interaction

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -26,6 +26,7 @@
#define __OPENSPACE_CORE___NAVIGATIONSTATE___H__
#include <openspace/documentation/documentation.h>
#include <openspace/json.h>
#include <optional>
namespace openspace {
@@ -37,12 +38,15 @@ namespace openspace::interaction {
struct NavigationState {
NavigationState() = default;
explicit NavigationState(const ghoul::Dictionary& dictionary);
explicit NavigationState(const nlohmann::json& json);
NavigationState(std::string anchor, std::string aim, std::string referenceFrame,
glm::dvec3 position, std::optional<glm::dvec3> up = std::nullopt,
double yaw = 0.0, double pitch = 0.0);
double yaw = 0.0, double pitch = 0.0,
std::optional<double> timestamp = std::nullopt);
CameraPose cameraPose() const;
ghoul::Dictionary dictionary() const;
nlohmann::json toJson() const;
static documentation::Documentation Documentation();
std::string anchor;
@@ -52,6 +56,8 @@ struct NavigationState {
std::optional<glm::dvec3> up;
double yaw = 0.0;
double pitch = 0.0;
std::optional<double> timestamp;
};
} // namespace openspace::interaction

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -37,16 +37,16 @@
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <openspace/properties/scalar/doubleproperty.h>
#include <openspace/properties/triggerproperty.h>
#include <openspace/util/syncdata.h>
#include <ghoul/glm.h>
#include <glm/gtx/quaternion.hpp>
#include <optional>
namespace openspace {
class SceneGraphNode;
class Camera;
struct CameraPose;
class SceneGraphNode;
struct SurfacePositionHandle;
} // namespace
@@ -88,10 +88,10 @@ public:
void updateCameraScalingFromAnchor(double deltaTime);
void resetVelocities();
/*
/**
* This function should be called on every camera interaction: for example when
* navigating using an input device, changing the focus node or starting a path or
* a session recording playback
* navigating using an input device, changing the focus node or starting a path or a
* session recording playback
*/
void updateOnCameraInteraction();
@@ -144,16 +144,18 @@ public:
glm::quat anchorNodeToCameraRotation() const;
/**
* Compute a camera position that pushed the camera position to
* a valid position over the anchor node, accounting for the
* minimal allowed distance
* Compute a camera position that pushed the camera position to a valid position over
* the anchor node, accounting for the minimal allowed distance
*/
glm::dvec3 pushToSurfaceOfAnchor(const glm::dvec3& cameraPosition) const;
void updateAnchor();
std::vector<Syncable*> syncables();
/**
* \return the Lua library that contains all Lua functions available to affect the
* OrbitalNavigator
*/
* \return The Lua library that contains all Lua functions available to affect the
* OrbitalNavigator
*/
static scripting::LuaLibrary luaLibrary();
private:
@@ -185,12 +187,11 @@ private:
Friction _friction;
// Anchor: Node to follow and orbit
/// Anchor: Node to follow and orbit
properties::StringProperty _anchor;
// Aim: Node to look at (when camera direction is reset),
// Empty string means same as anchor.
// If these are the same node we call it the `focus` node
/// Aim: Node to look at (when camera direction is reset), empty string means same as
/// anchor. If these are the same node we call it the `focus` node
properties::StringProperty _aim;
// Reset camera direction to the anchor node.
@@ -214,6 +215,9 @@ private:
LimitZoom _limitZoom;
properties::BoolProperty _disableZoom;
properties::BoolProperty _disableRoll;
properties::FloatProperty _mouseSensitivity;
properties::FloatProperty _joystickSensitivity;
properties::FloatProperty _websocketSensitivity;
@@ -230,11 +234,21 @@ private:
properties::BoolProperty _invertMouseButtons;
properties::BoolProperty _shouldRotateAroundUp;
enum class UpDirectionChoice {
XAxis = 0,
YAxis,
ZAxis
};
properties::OptionProperty _upToUseForRotation;
MouseCameraStates _mouseStates;
JoystickCameraStates _joystickStates;
WebsocketCameraStates _websocketStates;
ScriptCameraStates _scriptStates;
SyncData<std::string> _syncedAnchorNode;
const SceneGraphNode* _anchorNode = nullptr;
const SceneGraphNode* _aimNode = nullptr;
@@ -265,92 +279,107 @@ private:
* from the global to the current total rotation so that
* `cameraRotation = globalRotation * localRotation`.
*/
CameraRotationDecomposition decomposeCameraRotationSurface(const CameraPose pose,
const SceneGraphNode& reference);
CameraRotationDecomposition decomposeCameraRotationSurface(
const CameraPose& cameraPose, const SceneGraphNode& reference);
/**
* Decomposes the camera's rotation in to a global and a local rotation defined by
* CameraRotationDecomposition. The global rotation defines the rotation so that the
* camera points towards the reference position.
*
* The local rotation defines the differential from the global to the current total
* rotation so that `cameraRotation = globalRotation * localRotation`.
*/
CameraRotationDecomposition decomposeCameraRotation(const CameraPose pose,
glm::dvec3 reference);
CameraRotationDecomposition decomposeCameraRotation(const CameraPose& cameraPose,
const glm::dvec3& reference);
/**
* Composes a pair of global and local rotations into a quaternion that can be used
* as the world rotation for a camera.
* Composes a pair of global and local rotations into a quaternion that can be used as
* the world rotation for a camera.
*/
glm::dquat composeCameraRotation(const CameraRotationDecomposition& composition);
glm::dquat composeCameraRotation(
const CameraRotationDecomposition& decomposition) const;
/*
* Moves and rotates the camera around the anchor node in order to maintain the
* screen space position of the aim node. Also interpolates to the aim node, when
* retargeting the aim.
/**
* Moves and rotates the camera around the anchor node in order to maintain the screen
* space position of the aim node. Also interpolates to the aim node, when retargeting
* the aim.
*/
CameraPose followAim(CameraPose pose, glm::dvec3 cameraToAnchor,
Displacement anchorToAim);
CameraPose followAim(CameraPose pose, const glm::dvec3& cameraToAnchor,
const Displacement& anchorToAim);
/*
* Perform a camera roll on the local camera rotation
* \returns a local camera rotation modified with a roll.
/**
* Perform a camera roll on the local camera rotation.
*
* \return A local camera rotation modified with a roll
*/
glm::dquat roll(double deltaTime, const glm::dquat& localCameraRotation) const;
/**
* Performs rotation around the cameras x and y axes.
* \returns a local camera rotation modified with two degrees of freedom.
*
* \return A local camera rotation modified with two degrees of freedom
*/
glm::dquat rotateLocally(double deltaTime,
const glm::dquat& localCameraRotation) const;
/**
* Interpolates the camera rotation based on active interpolators.
* \returns a new rotation quaternion
*
* \return A new rotation quaternion
*/
glm::dquat interpolateLocalRotation(double deltaTime,
const glm::dquat& localCameraRotation);
Displacement interpolateRetargetAim(double deltaTime, CameraPose pose,
glm::dvec3 cameraToAnchor, Displacement anchorToAim);
Displacement interpolateRetargetAim(double deltaTime, const CameraPose& pose,
const glm::dvec3& prevCameraToAnchor, Displacement anchorToAim);
double interpolateCameraToSurfaceDistance(double deltaTime, double currentDistance,
double targetDistance);
/**
* Modify the camera position and global rotation to rotate around the up vector
* of the current anchor based on x-wise input.
*
* The up-vector to rotate around is determined by the "_upToUseForRotation" property
*/
void rotateAroundAnchorUp(double deltaTime, double speedScale,
glm::dvec3& cameraPosition, glm::dquat& globalCameraRotation);
/**
* Translates the horizontal direction. If far from the anchor object, this will
* result in an orbital rotation around the object. This function does not affect the
* rotation but only the position.
*
* \return a position vector adjusted in the horizontal direction.
* \return A position vector adjusted in the horizontal direction.
*/
glm::dvec3 translateHorizontally(double deltaTime, const glm::dvec3& cameraPosition,
const glm::dvec3& objectPosition, const glm::dquat& globalCameraRotation,
glm::dvec3 translateHorizontally(double deltaTime, double speedScale,
const glm::dvec3& cameraPosition, const glm::dvec3& objectPosition,
const glm::dquat& globalCameraRotation,
const SurfacePositionHandle& positionHandle) const;
/*
/**
* Adds rotation to the camera position so that it follows the rotation of the anchor
* node defined by the differential anchorNodeRotationDiff.
* node defined by the differential \p focusNodeRotationDiff.
*
* \return a position updated with the rotation defined by anchorNodeRotationDiff
* \return A position updated with the rotation defined by \p anchorNodeRotationDiff
*/
glm::dvec3 followAnchorNodeRotation(const glm::dvec3& cameraPosition,
const glm::dvec3& objectPosition, const glm::dquat& anchorNodeRotationDiff) const;
const glm::dvec3& objectPosition, const glm::dquat& focusNodeRotationDiff) const;
/**
* Updates the global rotation so that it points towards the anchor node.
*
* \return a global rotation quaternion defining a rotation towards the anchor node
* \return A global rotation quaternion defining a rotation towards the anchor node
*/
glm::dquat rotateGlobally(const glm::dquat& globalCameraRotation,
const glm::dquat& aimNodeRotationDiff,
const glm::dquat& focusNodeRotationDiff,
const SurfacePositionHandle& positionHandle) const;
/**
* Translates the camera position towards or away from the anchor node.
* \returns a position vector adjusted in the vertical direction.
*
* \return A position vector adjusted in the vertical direction.
*/
glm::dvec3 translateVertically(double deltaTime, const glm::dvec3& cameraPosition,
const glm::dvec3& objectPosition,
@@ -359,7 +388,7 @@ private:
/**
* Rotates the camera around the out vector of the surface.
*
* \return a quaternion adjusted to rotate around the out vector of the surface
* \return A quaternion adjusted to rotate around the out vector of the surface
*/
glm::dquat rotateHorizontally(double deltaTime,
const glm::dquat& globalCameraRotation,
@@ -368,7 +397,7 @@ private:
/**
* Push the camera out to the surface of the object.
*
* \return a position vector adjusted to be at least _minimumAllowedDistance meters
* \return A position vector adjusted to be at least _minimumAllowedDistance meters
* above the actual surface of the object
*/
glm::dvec3 pushToSurface(const glm::dvec3& cameraPosition,
@@ -387,16 +416,10 @@ private:
glm::dvec3 cameraToSurfaceVector(const glm::dvec3& cameraPos,
const glm::dvec3& centerPos, const SurfacePositionHandle& posHandle);
/**
* Calculates a SurfacePositionHandle given a camera position in world space.
*/
SurfacePositionHandle calculateSurfacePositionHandle(const SceneGraphNode& node,
const glm::dvec3& cameraPositionWorldSpace) const;
void resetIdleBehavior();
/**
* Apply the currently selected idle behavior to the position and rotations
* Apply the currently selected idle behavior to the position and rotations.
*/
void applyIdleBehavior(double deltaTime, glm::dvec3& position,
glm::dquat& localRotation, glm::dquat& globalRotation);
@@ -407,13 +430,11 @@ private:
*
* Used for IdleBehavior::Behavior::Orbit
*
* \param deltaTime The time step to use for the motion. Controls the rotation angle
* \param angle The rotation angle to use for the motion
* \param position The position of the camera. Will be changed by the function
* \param globalRotation The camera's global rotation. Will be changed by the function
* \param speedScale A speed scale that controls the speed of the motion
*/
void orbitAnchor(double deltaTime, glm::dvec3& position,
glm::dquat& globalRotation, double speedScale);
void orbitAnchor(double angle, glm::dvec3& position, glm::dquat& globalRotation);
/**
* Orbit the current anchor node, by adding a rotation around the given axis. For
@@ -422,17 +443,19 @@ private:
* vector coincides with the axis, and should be used with care.
*
* Used for:
* IdleBehavior::Behavior::OrbitAtConstantLat (axis = north = z-axis) and
* IdleBehavior::Behavior::OrbitAroundUp (axis = up = y-axis)
* - IdleBehavior::Behavior::OrbitAtConstantLat (axis = north = z-axis) and
* - IdleBehavior::Behavior::OrbitAroundUp (axis = up = y-axis)
*
* \param axis The axis to arbit around, given in model coordinates of the anchor
* \param deltaTime The time step to use for the motion. Controls the rotation angle
* \param angle The rotation angle to use for the motion
* \param position The position of the camera. Will be changed by the function
* \param globalRotation The camera's global rotation. Will be changed by the function
* \param speedScale A speed scale that controls the speed of the motion
*/
void orbitAroundAxis(const glm::dvec3 axis, double deltaTime, glm::dvec3& position,
glm::dquat& globalRotation, double speedScale);
void orbitAroundAxis(const glm::dvec3& axis, double angle, glm::dvec3& position,
glm::dquat& globalRotation);
double rotationSpeedScaleFromCameraHeight(const glm::dvec3& cameraPosition,
const SurfacePositionHandle& positionHandle) const;
};
} // namespace openspace::interaction

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -25,6 +25,7 @@
#ifndef __OPENSPACE_CORE___PATH___H__
#define __OPENSPACE_CORE___PATH___H__
#include <openspace/documentation/documentation.h>
#include <openspace/navigation/pathcurve.h>
#include <openspace/navigation/waypoint.h>
#include <ghoul/misc/dictionary.h>
@@ -43,119 +44,136 @@ public:
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
// remove it, and create a curve type that looks nicely
// at the targets when moving, avoids collisions and
// doesn't introduce sudden large changes in rotation
// @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 remove
// it, and create a curve type that looks nicely at the targets when moving,
// avoids collisions and doesn't introduce sudden large changes in rotation
AvoidCollisionWithLookAt
};
Path(Waypoint start, Waypoint end, Type type,
std::optional<double> duration = std::nullopt);
std::optional<float> duration = std::nullopt);
Waypoint startPoint() const;
Waypoint endPoint() const;
/**
* Return the total length of the the curve for the path, in meters
* Return the total length of the the curve for the path, in meters.
*/
double pathLength() const;
/**
* Return the remaining distance to traverse, in meters.
*/
double remainingDistance() const;
/**
* Estimate a value for the remaining time to reach the target, based on the
* currently progressed time and the estimation for how long the path will
* take to traverse. Note that the computation is not exact.
*
* \param speedScale The speed scale factor that may affect how fast the camera moves
* \return The estimated remaining time
*/
float estimatedRemainingTime(float speedScale) const;
/**
* Return a vector of positions corresponding to the control points of the path's
* spline curve
* spline curve.
*/
std::vector<glm::dvec3> controlPoints() const;
/**
* Take a step along the current path, corresponding to the delta time step \p dt, and
* return the resulting camera pose. The \p speedScale is a factor that will be
* multiplied with the traversal speed
* multiplied with the traversal speed.
*/
CameraPose traversePath(double dt, float speedScale = 1.f);
/**
* Function that can be used to permaturely quit a path, for example when skipping
* to the end
* to the end.
*/
void quitPath();
/**
* Return the identifer of the node that is the current appropriate anchor node, of
* the start and end waypoint's reference node. Dtermined based on how far along the
* path we have traveled
* path we have traveled.
*/
std::string currentAnchor() const;
/**
* Return wether the path has reached its end point or not
* Return wether the path has reached its end point or not.
*/
bool hasReachedEnd() const;
/**
* Compute the interpolated camera pose at a certain distance along a *linear*
* path. Note that the linear path is a special case, to avoid risks of precision
* problems for long paths
* problems for long paths.
*/
CameraPose linearInterpolatedPose(double distance, double displacement);
/**
* Compute the interpolated camera pose at a certain distance along the path
* Compute the interpolated camera pose at a certain distance along the path.
*/
CameraPose interpolatedPose(double distance) const;
/**
* Reset variables used to play back path
* Reset variables used to play back path.
*/
void resetPlaybackVariables();
static documentation::Documentation Documentation();
private:
/**
* Interpolate between the paths start and end rotation using the approach that
* corresponds to the path's curve type. The interpolation parameter \p t is the
* same as for the position interpolation, i.e. the relative traveled distance
* along the path, in [0, 1]
* corresponds to the path's curve type. The interpolation parameter \p t is the same
* as for the position interpolation, i.e. the relative traveled distance along the
* path, in [0, 1].
*
* \param t The interpolation parameter, given as the relative traveled distance
along the path, in [0, 1]
* \param t The interpolation parameter, given as the relative traveled distance along
* the path, in [0, 1]
*/
glm::dquat interpolateRotation(double t) const;
/**
* Compute the interpolated rotation quaternion using an eased SLERP approach
* Compute the interpolated rotation quaternion using an eased SLERP approach.
*
* \param t The interpolation variable for the rotatation interpolation.
* Should be the relative traveled distance, in [0, 1]
* \param t The interpolation variable for the rotatation interpolation. Should be the
* relative traveled distance, in [0, 1]
*/
glm::dquat easedSlerpRotation(double t) const;
/**
* Compute the interpolated rotation quaternion using a method that is customized
* for linear paths. The camera will first interpoalte to look at the targetted
* node, and keep doing so for most of the path. At the end, when within a certain
* distance from the target, the rotation is interpolated so that the camera ends up
* in the target pose at the end of the path.
* Compute the interpolated rotation quaternion using a method that is customized for
* linear paths. The camera will first interpoalte to look at the targetted node, and
* keep doing so for most of the path. At the end, when within a certain distance from
* the target, the rotation is interpolated so that the camera ends up in the target
* pose at the end of the path.
*
* \param t The interpolation variable for the rotatation interpolation.
* Should be the relative traveled distance, in [0, 1]
* \param t The interpolation variable for the rotatation interpolation. Should be the
* relative traveled distance, in [0, 1]
*/
glm::dquat linearPathRotation(double t) const;
/**
* Compute the interpolated rotation quaternion using an approach that first
* interpolates to look at the start node, and then the end node, before
* interpolating to the end rotation
* interpolates to look at the start node, and then the end node, before interpolating
* to the end rotation.
*
* \param t The interpolation variable for the rotatation interpolation.
* Should be the relative traveled distance, in [0, 1]
* \param t The interpolation variable for the rotatation interpolation. Should be the
* relative traveled distance, in [0, 1]
*/
glm::dquat lookAtTargetsRotation(double t) const;
/**
* Evaluate the current traversal speed along the path, based on the currently
* traveled distance. The final speed will be scaled to match the desired duration
* for the path (which might have been specified by the user)
* traveled distance. The final speed will be scaled to match the desired duration for
* the path (which might have been specified by the user).
*
* \param traveledDistance The current distance traveled along the path, in meters
*/
@@ -167,23 +185,24 @@ private:
std::unique_ptr<PathCurve> _curve;
double _speedFactorFromDuration = 1.0;
float _speedFactorFromDuration = 1.f;
float _expectedDuration = 0.f;
// Playback variables
double _traveledDistance = 0.0; // Meters
double _progressedTime = 0.0; // Time since playback started (seconds)
float _progressedTime = 0.f; // Time since playback started (seconds)
bool _shouldQuit = false;
CameraPose _prevPose;
};
/**
* Create a path based on an instruction given as a dictionary. (See top of cpp file
* for documentation on keys and values for the dictionary.)
* If /p forceType is specified, that type will primarily be used as the type for the
* created path. Secondly, the type will be read from the dictionary, and lastly it will
* use the default from PathNavigator.
* Create a path based on an instruction given as a dictionary (see top of cpp file
* for documentation on keys and values for the dictionary). If \p forceType is specified,
* that type will primarily be used as the type for the created path. Secondly, the type
* will be read from the dictionary, and lastly it will use the default from
* PathNavigator.
*
* \return the created path
* \return The created path
*/
Path createPathFromDictionary(const ghoul::Dictionary& dictionary,
std::optional<Path::Type> forceType = std::nullopt);

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -36,17 +36,17 @@ class Waypoint;
class PathCurve {
public:
struct InsufficientPrecisionError : public ghoul::RuntimeError {
explicit InsufficientPrecisionError(std::string msg);
explicit InsufficientPrecisionError(std::string error);
};
struct TooShortPathError : public ghoul::RuntimeError {
explicit TooShortPathError(std::string msg);
explicit TooShortPathError(std::string error);
};
virtual ~PathCurve() = 0;
/**
* Return the length of the curve, in meters
* Return the length of the curve, in meters.
*/
double length() const;
@@ -56,7 +56,7 @@ public:
* the full length of the path.
*
* Can be overridden by subclasses that want more control over the position
* interpolation
* interpolation.
*/
virtual glm::dvec3 positionAt(double relativeDistance) const;
@@ -66,27 +66,26 @@ public:
* position. Note that u does not correspond to the relatively traveled distance.
*
* Can be overridden by subclasses that want more control over the position
* interpolation
* interpolation.
*/
virtual glm::dvec3 interpolate(double u) const;
/**
* Return the positions defining the control points for the spline interpolation
* Return the positions defining the control points for the spline interpolation.
*/
std::vector<glm::dvec3> points() const;
protected:
/**
* Precompute information related to the spline parameters that are
* needed for arc length reparameterization. Must be called after
* control point creation.
* Precompute information related to the spline parameters that are needed for arc
* length reparameterization. Must be called after control point creation.
*/
void initializeParameterData();
/**
* Compute curve parameter u that matches the input arc length s.
* Input s is a length value in meters, in the range [0, _totalLength].
* The returned curve parameter u is in range [0, 1].
* Compute curve parameter u that matches the input arc length s. Input s is a length
* value in meters, in the range [0, _totalLength]. The returned curve parameter u is
* in range [0, 1].
*/
double curveParameter(double s) const;

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -64,6 +64,9 @@ public:
bool hasCurrentPath() const;
bool hasFinished() const;
bool isPlayingPath() const;
bool isPaused() const;
float estimatedRemainingTimeInPath() const;
void updateCamera(double deltaTime);
void createPath(const ghoul::Dictionary& dictionary);
@@ -78,30 +81,33 @@ public:
double minValidBoundingSphere() const;
double findValidBoundingSphere(const SceneGraphNode* node) const;
double defaultArrivalHeight(const std::string& sgnIdentifier) const;
const std::vector<SceneGraphNode*>& relevantNodes();
/**
* Find a node close to the given node. Closeness is determined by a factor times
* the bounding sphere of the object
* \return pointer to the SGN if one was found, nullptr otherwise
*/
* Find a node close to the given node. Closeness is determined by a factor times
* the bounding sphere of the object.
*
* \return Pointer to the SGN if one was found, nullptr otherwise
*/
static SceneGraphNode* findNodeNearTarget(const SceneGraphNode* node);
/**
* \return The Lua library that contains all Lua functions available to affect the
* path navigation
*/
* \return The Lua library that contains all Lua functions available to affect the
* path navigation
*/
static scripting::LuaLibrary luaLibrary();
private:
void handlePathEnd();
/**
* Populate list of nodes that are relevant for collision checks, etc
*/
* Populate list of nodes that are relevant for collision checks, etc.
*/
void findRelevantNodes();
void removeRollRotation(CameraPose& pose, double deltaTime);
void removeRollRotation(CameraPose& pose) const;
std::unique_ptr<Path> _currentPath = nullptr;
bool _isPlaying = false;

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -39,7 +39,7 @@ struct NavigationState;
class Waypoint {
public:
Waypoint() = default;
Waypoint(const glm::dvec3& pos, const glm::dquat& rot, const std::string& ref);
Waypoint(const glm::dvec3& pos, const glm::dquat& rot, std::string ref);
explicit Waypoint(const NavigationState& ns);
CameraPose pose() const;
@@ -47,6 +47,7 @@ public:
glm::dquat rotation() const;
SceneGraphNode* node() const;
std::string nodeIdentifier() const;
std::optional<std::string> aimIdentifier() const;
double validBoundingSphere() const;
private:
@@ -54,12 +55,17 @@ private:
std::string _nodeIdentifier;
// To be able to handle nodes with faulty bounding spheres
double _validBoundingSphere = 0.0;
// Keep track of if there was an aim node, specified in for example the
// navigation state used to create this waypoint. It may be required in
// certain situations
std::optional<std::string> _aimNodeIdentifier;
};
/**
* Compute a waypoint from the current camera position.
*
* \return the computed WayPoint
* \return The computed WayPoint
*/
Waypoint waypointFromCamera();
@@ -76,17 +82,17 @@ struct NodeCameraStateSpec {
* where the camera will be facing the given node. If there is a 'Sun' node in the scene,
* it will possibly be used to compute a position on the lit side of the object.
*
* \param spec details about the node and state to create the waypoint from. Minimal
* information is the identifier of the node, but a position or height
* above the bounding sphere may also be given.
* \param startPoint an optional previous waypoint. If not specified, the current camera
* \param spec Details about the node and state to create the waypoint from. Minimal
* information is the identifier of the node, but a position or height above
* the bounding sphere may also be given.
* \param startPoint An optional previous waypoint. If not specified, the current camera
* position will be used.
* \param userLinear if true, the new waypoint will be computed along a straight line
* from the start waypoint to the scene graph node or position.
* \return the computed WayPoint
* \param useLinear If `true`, the new waypoint will be computed along a straight line
* from the start waypoint to the scene graph node or position.
* \return The computed WayPoint
*/
Waypoint computeWaypointFromNodeInfo(const NodeCameraStateSpec& spec,
std::optional<Waypoint> startPoint = std::nullopt, bool useLinear = false);
const std::optional<Waypoint>& startPoint = std::nullopt, bool useLinear = false);
} // namespace openspace::interaction

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -25,9 +25,10 @@
#ifndef __OPENSPACE_CORE___MESSAGESTRUCTURES___H__
#define __OPENSPACE_CORE___MESSAGESTRUCTURES___H__
#include <ghoul/fmt.h>
#include <ghoul/format.h>
#include <ghoul/glm.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/stringhelper.h>
#include <algorithm>
#include <cstring>
#include <fstream>
@@ -49,8 +50,8 @@ struct CameraKeyframe {
CameraKeyframe(const std::vector<char>& buffer) {
deserialize(buffer);
}
CameraKeyframe(glm::dvec3&& pos, glm::dquat&& rot, std::string&& focusNode,
bool&& followNodeRot, float&& scale)
CameraKeyframe(glm::dvec3 pos, glm::dquat rot, std::string focusNode,
bool followNodeRot, float scale)
: _position(pos)
, _rotation(rot)
, _followNodeRotation(followNodeRot)
@@ -66,7 +67,7 @@ struct CameraKeyframe {
double _timestamp = 0.0;
void serialize(std::vector<char> &buffer) const {
void serialize(std::vector<char>& buffer) const {
// Add position
buffer.insert(
buffer.end(),
@@ -188,17 +189,14 @@ struct CameraKeyframe {
void write(std::stringstream& out) const {
// Add camera position
out << std::fixed << std::setprecision(7) << _position.x << ' '
<< std::fixed << std::setprecision(7) << _position.y << ' '
<< std::fixed << std::setprecision(7) << _position.z << ' ';
out << std::setprecision(std::numeric_limits<double>::max_digits10);
out << _position.x << ' ' << _position.y << ' ' << _position.z << ' ';
// Add camera rotation
out << std::fixed << std::setprecision(7) << _rotation.x << ' '
<< std::fixed << std::setprecision(7) << _rotation.y << ' '
<< std::fixed << std::setprecision(7) << _rotation.z << ' '
<< std::fixed << std::setprecision(7) << _rotation.w << ' ';
out << std::fixed
<< std::setprecision(std::numeric_limits<double>::max_digits10)
<< _scale << ' ';
out << _rotation.x << ' '
<< _rotation.y << ' '
<< _rotation.z << ' '
<< _rotation.w << ' ';
out << std::scientific << _scale << ' ';
if (_followNodeRotation) {
out << "F ";
}
@@ -407,7 +405,7 @@ struct ScriptMessage {
if (buffer.size() != (sizeof(uint32_t) + len)) {
LERRORC(
"ParallelPeer",
fmt::format(
std::format(
"Received buffer with wrong size. Expected {} got {}",
len, buffer.size()
)
@@ -468,7 +466,7 @@ struct ScriptMessage {
std::string tmpReadbackScript;
_script.erase();
for (int i = 0; i < numScriptLines; ++i) {
std::getline(iss, tmpReadbackScript);
ghoul::getline(iss, tmpReadbackScript);
size_t start = tmpReadbackScript.find_first_not_of(" ");
tmpReadbackScript = tmpReadbackScript.substr(start);
_script.append(tmpReadbackScript);

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -30,25 +30,27 @@
namespace openspace::datamessagestructures {
/**
* Method that creates a CameraKeyframe object and populates
* it with the current properties of the camera from the navigation handler.
* \returns CameraKeyframe with current state from NavigationHandler
* Method that creates a CameraKeyframe object and populates it with the current
* properties of the camera from the navigation handler.
*
* \return CameraKeyframe with current state from NavigationHandler
*/
CameraKeyframe generateCameraKeyframe();
/**
* Method that creates a TimeKeyframe object and populates
* it with the current time values from the application time manager.
* \returns TimeKeyframe The time keyframe
* Method that creates a TimeKeyframe object and populates it with the current time values
* from the application time manager.
*
* \return TimeKeyframe The time keyframe
*/
TimeKeyframe generateTimeKeyframe();
/**
* Method that creates a ScriptMessage object from a given script
* string, and populates the ScriptMessage with the script and timestamp
* of the current application time.
* Method that creates a ScriptMessage object from a given script string, and populates
* the ScriptMessage with the script and timestamp of the current application time.
*
* \param script The script to execute in std::string form
* \returns ScriptMessage The ScriptMessage data structure with script
* \return ScriptMessage The ScriptMessage data structure with script
*/
ScriptMessage generateScriptMessage(std::string script);

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -61,7 +61,7 @@ public:
struct DataMessage {
DataMessage() = default;
DataMessage(datamessagestructures::Type t, double timestamp, std::vector<char> c);
DataMessage(datamessagestructures::Type t, double time, std::vector<char> c);
datamessagestructures::Type type;
double timestamp;
@@ -70,7 +70,7 @@ public:
class ConnectionLostError : public ghoul::RuntimeError {
public:
explicit ConnectionLostError(bool shouldLogError = true);
explicit ConnectionLostError(bool shouldLogError_ = true);
bool shouldLogError;
};
@@ -86,7 +86,7 @@ public:
ParallelConnection::Message receiveMessage();
// Gonna do some UTF-like magic once we reach 255 to introduce a second byte or so
static constexpr uint8_t ProtocolVersion = 6;
static constexpr uint8_t ProtocolVersion = 7;
private:
std::unique_ptr<ghoul::io::TcpSocket> _socket;

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -52,6 +52,7 @@ public:
void connect();
void setPort(std::string port);
void setAddress(std::string address);
void setServerName(std::string name);
void setName(std::string name);
bool isHost();
const std::string& hostName();
@@ -66,9 +67,9 @@ public:
double latencyStandardDeviation() const;
/**
* Returns the Lua library that contains all Lua functions available to affect the
* remote OS parallel connection.
*/
* Returns the Lua library that contains all Lua functions available to affect the
* remote OS parallel connection.
*/
static scripting::LuaLibrary luaLibrary();
ParallelConnection::Status status();
int nConnections();
@@ -97,6 +98,7 @@ private:
properties::StringProperty _password;
properties::StringProperty _hostPassword;
properties::StringProperty _serverName;
// While the port should in theory be an int,
// we use a StringProperty to avoid a slider in the GUI.

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -73,9 +73,10 @@ protected:
std::string generateAdditionalJsonDescription() const override;
/**
* convert a lua formatted value to a JSON formatted value
* @param luaValue
* @return a json formatted string representation of the given lua value
* convert a lua formatted value to a JSON formatted value.
*
* \param luaValue
* \return A JSON formatted string representation of the given Lua value
*/
std::string luaToJson(std::string luaValue) const;

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -110,10 +110,10 @@ void NumericalProperty<T>::setExponent(float exponent) {
if (!isValidRange(_minimumValue, _maximumValue)) {
LWARNINGC(
"NumericalProperty: setExponent",
fmt::format(
std::format(
"Setting exponent for properties with negative values in "
"[min, max] range is not yet supported. Property: {}",
this->fullyQualifiedIdentifier()
this->uri()
)
);
_exponent = 1.f;

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -33,15 +33,15 @@ namespace openspace::properties {
/**
* The OptionProperty is a property that provides a number of predefined (using the
* addOption method) options consisting of a `description` and a `value`. The available
* #addOption method) options consisting of a `description` and a `value`. The available
* options can be queried using the options method. Only values representing valid options
* can be used to set this property, or an error will be logged
* can be used to set this property, or an error will be logged.
*/
class OptionProperty : public IntProperty {
public:
/**
* The struct storing a single option consisting of an integer `value` and a
* `string` description.
* The struct storing a single option consisting of an integer `value` and a `string`
* description.
*/
struct Option {
int value;
@@ -57,7 +57,8 @@ public:
* The constructor delegating the `identifier` and the `guiName` to its super class.
*
* \param info The PropertyInfo structure that contains all the required static
* information for initializing this Property.
* information for initializing this Property
*
* \pre \p info.identifier must not be empty
* \pre \p info.guiName must not be empty
*/
@@ -67,7 +68,7 @@ public:
* The constructor delegating the `identifier` and the `guiName` to its super class.
*
* \param info The PropertyInfo structure that contains all the required static
* information for initializing this Property.
* information for initializing this Property
* \param displayType Optional DisplayType for GUI (default RADIO)
*
* \pre \p info.identifier must not be empty
@@ -123,7 +124,7 @@ public:
const std::vector<Option>& options() const;
/**
* This function removes all previous options from the OptionProperty
* This function removes all previous options from the OptionProperty.
*/
void clearOptions();
@@ -151,10 +152,10 @@ public:
const Option& option() const;
/**
* Get the description of the option that matches `value`.
*
* \param value The value of the option
*/
* Get the description of the option that matches `value`.
*
* \param value The value of the option
*/
std::string getDescriptionByValue(int value);
private:

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -41,8 +41,8 @@ class PropertyOwner;
/**
* A property encapsulates a value which should be user-changeable. A property almost
* always belongs to a PropertyOwner who has taken ownership (setPropertyOwner) of the
* Property. Per PropertyOwner, the `identifier` needs to be unique and can be
* used as a URI. This class is an abstract base class and each subclass (most notable
* Property. Per PropertyOwner, the `identifier` needs to be unique and can be used as a
* URI. This class is an abstract base class and each subclass (most notable
* TemplateProperty) needs to implement the methods Property::className, Property::get,
* Property::set, Property::type(), Property::getLuaValue, Property::setLuaValue,
* Property::getStringValue, and Property::typeLua to make full use of the infrastructure.
@@ -56,24 +56,32 @@ class PropertyOwner;
* which might be used in GUI representations. One example would be a glm::vec4 property,
* (Vec4Property) that can either represent a 4-dimensional position, a powerscaled
* coordinate, a light position, or other things, requiring different GUI representations.
*
* \see TemplateProperty
* \see PropertyOwner
*/
class Property {
public:
/**
* The visibility classes for Property%s. The classes are strictly ordered as
* Hidden > Developer > AdvancedUser > User > NoviceUser > Always
*/
* The visibility classes for Property%s. The classes are strictly ordered as
* Hidden > Developer > AdvancedUser > User > NoviceUser > Always
*/
enum class Visibility {
Hidden = 5, ///< Never visible
Developer = 4, ///< Visible in Developer mode
AdvancedUser = 3, ///< Visible in Advanced User mode
User = 2, ///< Visible in User mode
NoviceUser = 1, ///< Visible in Novice User mode
Always = 0, ///< Visible for all types, no matter what
/// Never visible
Hidden = 5,
/// Visible in Developer mode
Developer = 4,
/// Visible in Advanced User mode
AdvancedUser = 3,
/// Visible in User mode
User = 2,
/// Visible in Novice User mode
NoviceUser = 1,
/// Visible for all types, no matter what
Always = 0,
Default = Always ///< The default visibility for properties
/// The default visibility for properties
Default = Always
};
/**
@@ -81,8 +89,10 @@ public:
* identifier, a GUI name and descriptive text that are both user facing.
*/
struct PropertyInfo {
/// GCC requires an explicit constructor here, as it does not handle the default
/// argument for the struct initialization
/**
* GCC requires an explicit constructor here, as it does not handle the default
* argument for the struct initialization.
*/
constexpr PropertyInfo(const char* ident, const char* gui, const char* desc)
: identifier(ident)
, guiName(gui)
@@ -208,9 +218,9 @@ public:
* Returns the Lua type that will be put onto the stack in the Property::getLua method
* and which will be consumed by the Property::setLuaValue method. The returned value
* can belong to the set of Lua types: `LUA_TNONE`, `LUA_TNIL`, `LUA_TBOOLEAN`,
* `LUA_TLIGHTUSERDATA`, `LUA_TNUMBER`, `LUA_TSTRING`, `LUA_TTABLE`,
* `LUA_TFUNCTION`, `LUA_TUSERDATA`, or `LUA_TTHREAD`. The default implementation
* will return `LUA_TNONE`.
* `LUA_TLIGHTUSERDATA`, `LUA_TNUMBER`, `LUA_TSTRING`, `LUA_TTABLE`, `LUA_TFUNCTION`,
* `LUA_TUSERDATA`, or `LUA_TTHREAD`. The default implementation will return
* `LUA_TNONE`.
*
* \return The Lua type that will be consumed or produced by the Property::getLuaValue
* and Property::setLuaValue methods.
@@ -237,18 +247,18 @@ public:
* Property::setLuaValue methods.
* \return An OnChangeHandle that can be used in subsequent calls to remove a callback
*
* \pre The callback must not be empty
* \pre The \p callback must not be empty
*/
OnChangeHandle onChange(std::function<void()> callback);
/**
* This method registers a \p callback function that will be called when the property
* is destructed.
*
* \return An OnDeleteHandle that can be used in subsequent calls to remove a callback
*
* \pre The callback must not be empty
*/
* This method registers a \p callback function that will be called when the property
* is destructed.
*
* \return An OnDeleteHandle that can be used in subsequent calls to remove a callback
*
* \pre The \p callback must not be empty
*/
OnDeleteHandle onDelete(std::function<void()> callback);
/**
@@ -265,15 +275,15 @@ public:
void removeOnChange(OnChangeHandle handle);
/**
* This method deregisters a callback that was previously registered with the onDelete
* method.
*
* \param handle An OnDeleteHandle that was returned from a previous call to onDelete
* by this property.
*
* \pre \p handle must refer to a callback that has been previously registred
* \pre \p handle must refer to a callback that has not been removed previously
*/
* This method deregisters a callback that was previously registered with the onDelete
* method.
*
* \param handle An OnDeleteHandle that was returned from a previous call to onDelete
* by this property.
*
* \pre \p handle must refer to a callback that has been previously registred
* \pre \p handle must refer to a callback that has not been removed previously
*/
void removeOnDelete(OnDeleteHandle handle);
/**
@@ -284,19 +294,21 @@ public:
const std::string& identifier() const;
/**
* Returns the fully qualified name for this Property that uniquely identifies this
* Property within OpenSpace. It consists of the identifier preceded by all levels of
* PropertyOwner%s separated with `.`; for example: `owner1.owner2.identifier`.
* Returns the URI for this Property that uniquely identifies this Property within
* OpenSpace. It consists of the identifier preceded by all levels of PropertyOwner%s
* separated with `.`; for example: `owner1.owner2.identifier`. If the URI is invalid
* (the Property hasn't been added to the property tree yet), it returns an empty
* string.
*
* \return The fully qualified identifier for this Property
*/
std::string fullyQualifiedIdentifier() const;
std::string uri() const;
/**
* Returns the PropertyOwner of this Property or `nullptr`, if it does not have an
* owner.
*
* \return The Property of this Property
* \return The PropertyOwner of this Property
*/
PropertyOwner* owner() const;
@@ -337,8 +349,9 @@ public:
void setGroupIdentifier(std::string groupId);
/**
* Returns the group idenfier that this Property belongs to, or `""` if it
* belongs to no group.
* Returns the group idenfier that this Property belongs to, or `""` if it belongs to
* no group.
*
* \return The group identifier that this Property belongs to
*/
std::string groupIdentifier() const;
@@ -363,18 +376,29 @@ public:
* This method determines if this Property should be read-only in external
* applications. This setting is only a hint and does not need to be followed by GUI
* applications and does not have any effect on the Property::set or
* Property::setLuaValue methods. The value is stored in the metaData Dictionary
* with the key: `isReadOnly`. The default value is `false`.
* Property::setLuaValue methods. The value is stored in the metaData Dictionary with
* the key: `isReadOnly`. The default value is `false`.
*
* \param state `true` if the Property should be read only, `false` otherwise
*/
void setReadOnly(bool state);
/**
* This method determines if this Property requires confirmation upon every change of
* the value. This setting is only a hint and does not need to be followed by GUI
* applications and does not have any effect on the Property::set or
* Property::setLuaValue methods. The value is stored in the metaData Dictionary with
* the key: `needsConfirmation`. The default value is `false`.
*
* \param state `true` if the Property needs confirmation, `false` otherwise
*/
void setNeedsConfirmation(bool state);
/**
* Default view options that can be used in the Property::setViewOption method. The
* values are:
* - Property::ViewOptions::Color = `Color` (Intended for Vec3 and Vec4),
* - Property::ViewOptions::MinMaxRange = `MinMaxRange` (Intended for Vec2)
* - Property::ViewOptions::Color = `Color` (Intended for Vec3 and Vec4),
* - Property::ViewOptions::MinMaxRange = `MinMaxRange` (Intended for Vec2)
*/
struct ViewOptions {
static const char* Color;
@@ -385,9 +409,10 @@ public:
* This method allows the developer to give hints to the GUI about different
* representations for the GUI. The same Property (for example Vec4Property) can be
* used in different ways, each requiring a different input method. These values are
* stored in the metaData object under `ViewOptions`.
* See Property::ViewOptions for a default list of possible options. As these are
* only hints, the GUI is free to ignore any suggestion by the developer.
* stored in the metaData object under `ViewOptions`. See Property::ViewOptions for a
* default list of possible options. As these are only hints, the GUI is free to
* ignore any suggestion by the developer.
*
* \param option The view option that should be modified
* \param value Determines if the view option should be active (`true`) or
* deactivated (`false`)
@@ -401,7 +426,6 @@ public:
*
* \param option The view option that should be retrieved
* \param defaultValue The value that is returned if the \p option was not set
*
* \return The view option's value
*/
bool viewOption(const std::string& option, bool defaultValue = false) const;
@@ -418,7 +442,7 @@ public:
/**
* Get a valid JSON formatted representation of the Property's value.
*
* \return the value in a json compatible format
* \return The value in a JSON compatible format
*/
virtual std::string jsonValue() const;
@@ -431,8 +455,8 @@ public:
/**
* Creates the information that is general to every Property and adds the
* `Identifier`, `Name`, `Type`, and `MetaData` keys and their values. The meta
* data is handles by the generateMetaDataJsonDescription method, which has to be
* `Identifier`, `Name`, `Type`, and `MetaData` keys and their values. The meta data
* is handles by the generateMetaDataJsonDescription method, which has to be
* overloaded if a concrete base class wants to add meta data that is not curated by
* the Property class.
*

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -25,7 +25,6 @@
#ifndef __OPENSPACE_CORE___PROPERTYOWNER___H__
#define __OPENSPACE_CORE___PROPERTYOWNER___H__
#include <openspace/json.h>
#include <map>
#include <string>
#include <vector>
@@ -53,7 +52,7 @@ public:
static constexpr char URISeparator = '.';
struct PropertyOwnerInfo {
std::string identifier;
std::string identifier = "";
std::string guiName = "";
std::string description = "";
};
@@ -63,7 +62,7 @@ public:
*
* \param info The PropertyOwnerInfo struct that contains the
* #PropertyOwnerInfo::identifier, #PropertyOwnerInfo::guiName, and
* #PropertyOwnerInfo::description of this PropertyOwner.
* #PropertyOwnerInfo::description of this PropertyOwner
*
* \pre The \p info 's #PropertyOwnerInfo::identifier must not contain any whitespaces
* \pre The \p info 's #PropertyOwnerInfo::identifier must not contain any `.`
@@ -141,33 +140,57 @@ public:
/**
* Retrieves a Property identified by \p uri from this PropertyOwner. If \p uri does
* not contain a `.` the identifier must refer to a Property directly owned
* by this PropertyOwner. If the identifier contains one or more `.`, the
* first part of the name will be recursively extracted and used as a name for a
* sub-owner and only the last part of the identifier is referring to a Property owned
* by PropertyOwner named by the second-but-last name.
* not contain a `.` it is an identifier and must refer to a Property directly owned
* by this PropertyOwner. If the identifier contains one or more `.`, the first part
* of the name will be recursively extracted and used as a name for a sub-owner and
* only the last part of the identifier is referring to a Property owned by a
* PropertyOwner named by the second-but-last name.
*
* \param uri The identifier of the Property that should be extracted
* \param uri The uri or identifier of the Property that should be extracted
* \return If the Property cannot be found, `nullptr` is returned, otherwise the
* pointer to the Property is returned
*/
Property* property(const std::string& uri) const;
/**
* This method checks if a Property with the provided \p uri exists in this
* PropertyOwner (or any sub-owner). If the identifier contains one or more
* `.`, the first part of the name will be recursively extracted and is
* used as a name for a sub-owner and only the last part of the identifier is
* referring to a Property owned by PropertyOwner named by the second-but-last name.
* Retrieves a PropertyOwner identified by \p uri from this PropertyOwner. If \p uri
* does not contain a `.` it is an identifier and must refer to a PropertyOwner
* directly owned by this PropertyOwner. If the uri contains one or more `.`, the
* first part of the name will be recursively extracted and used as a name for a sub-
* owner and only the last part of the uri is referring to a PropertyOwner owned by a
* PropertyOwner named by the second-but-last name.
*
* \return `true` if the \p uri refers to a Property; `false` otherwise.
* \param uri The uri or identifier of the PropertyOwner that should be extracted
* \return If the PropertyOwner cannot be found, `nullptr` is returned, otherwise the
* pointer to the PropertyOwner is returned
*/
PropertyOwner* propertyOwner(const std::string& uri) const;
/**
* Returns a uri for this PropertyOwner. This is created by looking up all the owners
* of this PropertyOwner. The owner identifiers are separated by ".", which make up
* the uri of this PropertyOwner.
*
* \return The uri of this PropertyOwner
*/
std::string uri() const;
/**
* This method checks if a Property with the provided \p uri exists in this
* PropertyOwner (or any sub-owner). If the identifier contains one or more `.`, the
* first part of the name will be recursively extracted and is used as a name for a
* sub-owner and only the last part of the identifier is referring to a Property owned
* by PropertyOwner named by the second-but-last name.
*
* \return `true` if the \p uri refers to a Property; `false` otherwise
*/
bool hasProperty(const std::string& uri) const;
/**
* This method checks if a Property exists in this PropertyOwner.
* \return `true` if the Property existed, `false` otherwise.
*/
* This method checks if a Property exists in this PropertyOwner.
*
* \return `true` if the Property existed, `false` otherwise
*/
bool hasProperty(const Property* prop) const;
void setPropertyOwner(PropertyOwner* owner) { _owner = owner; }
@@ -185,11 +208,11 @@ public:
/**
* This method returns the direct sub-owner of this PropertyOwner with the provided
* \p identifier. This means that `identifier` cannot contain any `.` as this
* character is not allowed in PropertyOwner names. If the \p name does not name a
* valid sub-owner of this PropertyOwner, a `nullptr` will be returned.
* character is not allowed in PropertyOwner names. If the \p identifier does not name
* a valid sub-owner of this PropertyOwner, a `nullptr` will be returned.
*
* \param identifier The identifier of the sub-owner that should be returned
* \return The PropertyOwner with the given \p name, or `nullptr`
* \return The PropertyOwner with the given \p identifier, or `nullptr`
*/
PropertyOwner* propertySubOwner(const std::string& identifier) const;
@@ -294,9 +317,6 @@ public:
*/
void removeTag(const std::string& tag);
// Generate JSON for documentation
nlohmann::json generateJson() const;
protected:
/// The unique identifier of this PropertyOwner
std::string _identifier;

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -25,19 +25,6 @@
#ifndef __OPENSPACE_CORE___SHORTPROPERTY___H__
#define __OPENSPACE_CORE___SHORTPROPERTY___H__
/**
* \file shortproperty.h
*
* \addtogroup openspace
* @{
* \addtogroup properties
* @{
* \class ShortProperty
* @} @}
*/
#include <openspace/properties/numericalproperty.h>
#include <limits>

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -41,10 +41,10 @@ public:
int typeLua() const override;
/**
* This method sets the stored value to the provided value `val`.
* If the value is different, the listeners are notified. It also removes any
* invalid keys in the input set. A key is invalid if it does not correspond to
* an existing option in the SelectionProperty
* This method sets the stored value to the provided value `val`. If the value is
* different, the listeners are notified. It also removes any invalid keys in the
* input set. A key is invalid if it does not correspond to an existing option in the
* SelectionProperty.
*
* \param val The new value for this SelectionProperty
*/
@@ -67,16 +67,16 @@ public:
bool isSelected(const std::string& key) const;
/**
* Checks if the SelectionProperty has any selected values, that is, if its
* value is empty.
* Checks if the SelectionProperty has any selected values, that is, if its value is
* empty.
*
* \return `true` if there are selected options; `false` otherwise
*/
bool hasSelected() const;
/**
* Returns all available options for this SelectionProperty. Should be
* sorted alphabetically.
* Returns all available options for this SelectionProperty. Should be sorted
* alphabetically.
*
* \return A list of all available options
*/
@@ -99,7 +99,7 @@ public:
void addOption(const std::string& key);
/**
* This method clears the selection list, that is the value of this SelectionProperty
* This method clears the selection list, that is the value of this SelectionProperty.
*/
void clearSelection();
@@ -122,7 +122,7 @@ protected:
private:
void sortOptions();
bool removeInvalidKeys(std::set<std::string>& keys);
bool removeInvalidKeys(std::set<std::string>& keys) const;
std::string generateAdditionalJsonDescription() const override;

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -30,20 +30,21 @@
namespace openspace::properties {
/**
* This subclass of Property handles a single parameter value that is of type
* `T`. It provides all the necessary methods to automatically access the
* value. One notable instantiation of this class is StringProperty, using
* `T = std::string` while NumericalProperty is a templated subclass dealing
* with numerical parameter types.
* This subclass of Property handles a single parameter value that is of type `T`. It
* provides all the necessary methods to automatically access the value. One notable
* instantiation of this class is StringProperty, using `T = std::string` while
* NumericalProperty is a templated subclass dealing with numerical parameter types.
*
* The accessor operator and assignment operators are overloaded, so that the
* TemplateProperty can be used just in the same way as a regular member variable. In the
* case that these cannot not be used inline, the Property::get method will work.
*
* Each instantiation of this class should provide a constructor that deals with the
* default value for that specific type `T`, so that a property can be
* created from just a Property::PropertyInfo object.
* default value for that specific type `T`, so that a property can be created from just a
* Property::PropertyInfo object.
*
* \tparam T The type of value that is stored in this TemplateProperty
*
* \see Property
* \see NumericalProperty
*/
@@ -66,33 +67,31 @@ public:
TemplateProperty(Property::PropertyInfo info, T value);
/**
* Returns the class name for this TemplateProperty. This method has to be
* specialized for each new type.
* Returns the class name for this TemplateProperty. This method has to be specialized
* for each new type.
*
* \return The class name for the TemplateProperty
*/
virtual std::string_view className() const override = 0;
/**
* Returns the stored value packed into a ghoul::any object.
* Returns the stored value packed into a `std::any` object.
*
* \return The stored value packed into a ghoul::any object
* \return The stored value packed into a `std::any` object
*/
virtual std::any get() const override;
/**
* Sets the value from the provided ghoul::any object. If the types between
* `T` and `value` disagree, an error is logged and the stored
* value remains unchanged.
* Sets the value from the provided ghoul::any object. If the types between `T` and
* `value` disagree, an error is logged and the stored value remains unchanged.
*
* \param value The value that is used to set this Property
*/
virtual void set(std::any value) final;
/**
* Returns the `std::type_info` describing the template parameter
* `T`. It can be used to test against a ghoul::any value before trying to
* assign it.
* Returns the `std::type_info` describing the template parameter `T`. It can be used
* to test against a ghoul::any value before trying to assign it.
*
* \return The type info object describing the template parameter `T`
*/
@@ -113,7 +112,6 @@ public:
* decoding is successful, the new value is set, otherwise it remains unchanged.
*
* \param state The Lua state from which the value will be decoded
* \return `true` if the decoding succeeded; `false` otherwise
*/
virtual void setLuaValue(lua_State* state) override;
@@ -128,19 +126,11 @@ public:
*/
virtual std::string stringValue() const override;
/**
* Returns the description for this TemplateProperty as a Lua script that returns a
* table on execution.
*
* \return The description for this TemplateProperty
*/
//virtual std::string description() override;
/**
* This operator allows the TemplateProperty to be used almost transparently as if it
* was of the type `T`. It makes assignments such as
* `T v = property;` possible by allowing implicit casts (even though,
* internally, not casts are performed. This method is next to zero overhead).
* was of the type `T`. It makes assignments such as `T v = property;` possible by
* allowing implicit casts (even though, internally, not casts are performed. This
* method is next to zero overhead).
*
* \return The internal representation of the Property
*/
@@ -148,9 +138,9 @@ public:
/**
* This operator allows the TemplateProperty to be used almost transparently as if it
* was of the type `T`. It makes assignments such as
* `T v = property;` possible by allowing implicit casts (even though,
* internally, not casts are performed. This method is next to zero overhead).
* was of the type `T`. It makes assignments such as `T v = property;` possible by
* allowing implicit casts (even though, internally, not casts are performed. This
* method is next to zero overhead).
*
* \return The internal representation of the Property
*/
@@ -166,10 +156,10 @@ public:
TemplateProperty<T>& operator=(T val);
/**
* This method sets the stored value to the provided value `val`,
* moving it into place. The move only happens if the provided value `val`
* is different from the stored value, which needs an operator== to exist for the type
* `T`. If the value is different, the listeners are notified.
* This method sets the stored value to the provided value `val`, moving it into
* place. The move only happens if the provided value `val` is different from the
* stored value, which needs an operator== to exist for the type `T`. If the value is
* different, the listeners are notified.
*
* \param val The new value for this TemplateProperty
*/
@@ -184,17 +174,17 @@ public:
protected:
/**
* Decodes the object at the top of the stack to a value of the type `T`
* and returns it. This method has to be specialized for each new type.
* Decodes the object at the top of the stack to a value of the type `T` and returns
* it. This method has to be specialized for each new type.
*
* \param state The Lua state from which the value will be decoded
* \return the decoded value
* \return The decoded value
*/
virtual T fromLuaConversion(lua_State* state) const = 0;
/**
* Encodes the stored value into a Lua object and pushes that object onto
* the stack. This method has to be specialized for each new type.
* Encodes the stored value into a Lua object and pushes that object onto the stack.
* This method has to be specialized for each new type.
*
* \param state The Lua state onto which the encoded object will be pushed
*/
@@ -202,8 +192,8 @@ protected:
/**
* Encodes the stored value into a std::string object, in a format that is a valid
* JSON representation of the property. This method has to be specialized for each
* new type.
* JSON representation of the property. This method has to be specialized for each new
* type.
*
* \return The resulting encoding
*/

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *
@@ -36,10 +36,11 @@ namespace openspace::properties {
class TriggerProperty : public Property {
public:
/**
* Initializes the TriggerProperty by delegating the `identifier` and
* `guiName` to the Property constructor.
* Initializes the TriggerProperty by delegating the `identifier` and `guiName` to the
* Property constructor.
*
* \param info The PropertyInfo structure that contains all the required static
* information for initializing this Property.
* information for initializing this Property
* \pre \p info.identifier must not be empty
* \pre \p info.guiName must not be empty
*/
@@ -47,25 +48,32 @@ public:
/**
* Returns the class name `TriggerProperty`.
*
* \return The class name `TriggerProperty`
*/
std::string_view className() const override;
/**
* Accepts only the `LUA_TNIL` type and will notify all the listeners
* that the event has been triggered.
* Accepts only the `LUA_TNIL` type and will notify all the listeners that the event
* has been triggered.
*
* \param state The unused Lua state
* \return Returns always `true`
*/
void setLuaValue(lua_State* state) override;
/**
* Silently ignores any value that is passed into this function and will trigger the
* listeners regardless of the value
*
* \param value The ignored value
*/
void set(std::any value) override;
/**
* Triggers this TriggerProperty.
*/
void trigger();
std::string jsonValue() const override;
};

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

View File

@@ -2,7 +2,7 @@
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* Copyright (c) 2014-2025 *
* *
* 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 *

Some files were not shown because too many files have changed in this diff Show More