Merge remote-tracking branch 'origin/master' into thesis/2020/radiation

This commit is contained in:
ElonOlsson
2021-03-12 15:15:58 -05:00
35 changed files with 1298 additions and 579 deletions

View File

@@ -203,6 +203,12 @@ begin_header("Configuring Applications")
add_subdirectory("${OPENSPACE_APPS_DIR}")
end_header("End: Configuring Applications")
if (MSVC AND TARGET OpenSpace)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT OpenSpace)
endif()
option(OPENSPACE_HAVE_TESTS "Activate the OpenSpace unit tests" ON)
if (OPENSPACE_HAVE_TESTS)
begin_header("Generating OpenSpace unit test")

View File

@@ -660,6 +660,17 @@ void mainCharCallback(unsigned int codepoint, int modifiers) {
void mainDropCallback(int amount, const char** paths) {
ghoul_assert(amount > 0, "Expected at least one file path");
ghoul_assert(paths, "expected non-nullptr");
for (int i = 0; i < amount; ++i) {
global::openSpaceEngine->handleDragDrop(paths[i]);
}
}
std::vector<std::byte> mainEncodeFun() {
ZoneScoped
LTRACE("main::mainEncodeFun(begin)");
@@ -1025,7 +1036,6 @@ int main(int argc, char* argv[]) {
{
using namespace ghoul::logging;
LogManager::initialize(LogLevel::Debug, LogManager::ImmediateFlush::Yes);
LogMgr.addLog(std::make_unique<ConsoleLog>());
#ifdef WIN32
if (IsDebuggerPresent()) {
LogMgr.addLog(std::make_unique<ghoul::logging::VisualStudioOutputLog>());
@@ -1252,6 +1262,7 @@ int main(int argc, char* argv[]) {
callbacks.mousePos = mainMousePosCallback;
callbacks.mouseScroll = mainMouseScrollCallback;
callbacks.character = mainCharCallback;
callbacks.drop = mainDropCallback;
callbacks.encode = mainEncodeFun;
callbacks.decode = mainDecodeFun;
Log::instance().setNotifyLevel(Log::Level::Debug);

View File

@@ -4,6 +4,14 @@ local DataPath = asset.syncedResource({
Identifier = "exoplanets_data",
Version = 2
})
asset.onInitialize(function ()
local p = "Modules.Exoplanets.DataFolder";
if(openspace.getPropertyValue(p) == "") then
openspace.setPropertyValueSingle(p, DataPath)
end
end)
asset.export("DataPath", DataPath)
asset.meta = {

View File

@@ -1,4 +1,5 @@
asset.require('./../habitable_zones/habitable_zone_textures')
local habitableZoneTextures =
asset.require('./../habitable_zones/habitable_zone_textures').TexturesPath
local TexturesPath = asset.syncedResource({
Name = "Exoplanet Textures",
@@ -6,6 +7,37 @@ local TexturesPath = asset.syncedResource({
Identifier = "exoplanets_textures",
Version = 2
})
asset.onInitialize(function ()
local starTexture = TexturesPath .. "/sun.jpg"
local noDataTexture = TexturesPath .. "/grid-32.png"
local discTexture = TexturesPath .. "/disc_bw_texture.png"
local hzTexture = habitableZoneTextures .. "/hot_to_cold_faded.png"
-- Set the default textures used for the exoplanet system creation
-- (Check if already set, to not override value in config file)
local p = "Modules.Exoplanets.StarTexture";
if(openspace.getPropertyValue(p) == "") then
openspace.setPropertyValueSingle(p, starTexture)
end
p = "Modules.Exoplanets.NoDataTexture";
if(openspace.getPropertyValue(p) == "") then
openspace.setPropertyValueSingle(p, noDataTexture)
end
p = "Modules.Exoplanets.OrbitDiscTexture";
if(openspace.getPropertyValue(p) == "") then
openspace.setPropertyValueSingle(p, discTexture)
end
p = "Modules.Exoplanets.HabitableZoneTexture";
if(openspace.getPropertyValue(p) == "") then
openspace.setPropertyValueSingle(p, hzTexture)
end
end)
asset.export("TexturesPath", TexturesPath)
asset.meta = {

View File

@@ -85,7 +85,9 @@ function satellites(title, file, color, group)
SegmentQuality = 3,
Color = color,
Fade = 1.5,
RenderBinMode = "PostDeferredTransparent"
RenderBinMode = "PostDeferredTransparent",
StartRenderIdx = group.StartRenderIdx,
RenderSize = group.RenderSize
},
Tag = { "earth_satellites" },
GUI = {

View File

@@ -66,6 +66,8 @@ struct TestResult {
std::string offender;
/// The Reason that caused this offense
Reason reason;
/// An optional explanation for when a verification fails
std::string explanation;
};
/**
@@ -79,7 +81,7 @@ struct TestResult {
* The reason for the warning
*/
enum class Reason {
Deprecated ///< The value is marked as deprecated and should not used
Deprecated ///< The value is marked as deprecated and should not used
};
/// The offending key that caused the Warning. In the case of a nested table,

View File

@@ -158,6 +158,28 @@ struct StringVerifier : public TemplateVerifier<std::string> {
std::string type() const override;
};
/**
* A Verifier that checks whether a given key inside a ghoul::Dictionary is a string and
* refers to an existing file on disk.
*/
struct FileVerifier : public StringVerifier {
TestResult operator()(const ghoul::Dictionary& dict,
const std::string& key) const override;
std::string type() const override;
};
/**
* A Verifier that checks whether a given key inside a ghoul::Dictionary is a string and
* refers to an existing directory on disk.
*/
struct DirectoryVerifier : public StringVerifier {
TestResult operator()(const ghoul::Dictionary& dict,
const std::string& key) const override;
std::string type() const override;
};
/**
* A Verifier that checks whether a given key inside a ghoul::Dictionary is another
* ghoul::Dictionary. The constructor takes a list of DocumentationEntry%s, which are used
@@ -243,39 +265,48 @@ struct IntListVerifier : public TableVerifier {
*/
struct VectorVerifier {};
/**
* This Verifier checks whether the value is of type <code>glm::tvec2<T></code>
*/
/// This Verifier checks whether the value is of type <code>glm::tvec2<T></code>
template <typename T>
struct Vector2Verifier : public TemplateVerifier<glm::tvec2<T>>, public VectorVerifier {
std::string type() const override;
};
/**
* This Verifier checks whether the value is of type <code>glm::tvec3<T></code>
*/
/// This Verifier checks whether the value is of type <code>glm::tvec3<T></code>
template <typename T>
struct Vector3Verifier : public TemplateVerifier<glm::tvec3<T>>, public VectorVerifier {
std::string type() const override;
};
/**
* This Verifier checks whether the value is of type <code>glm::tvec4<T></code>
*/
/// This Verifier checks whether the value is of type <code>glm::tvec4<T></code>
template <typename T>
struct Vector4Verifier : public TemplateVerifier<glm::tvec4<T>>, public VectorVerifier {
std::string type() const override;
};
struct Color3Verifier : public Vector3Verifier<double> {
TestResult operator()(const ghoul::Dictionary& dictionary,
const std::string& key) const override;
std::string type() const override;
};
struct Color4Verifier : public Vector4Verifier<double> {
TestResult operator()(const ghoul::Dictionary& dictionary,
const std::string& key) const override;
std::string type() const override;
};
/**
* A Verifier that checks whether all values contained in a Table are of
* type <code>glm::tvec2<T></code>
*/
template <typename T>
struct Vector2ListVerifier : public TableVerifier {
Vector2ListVerifier(std::string elementDocumentation = "") : TableVerifier({
Vector2ListVerifier(std::string elementDocumentation = "")
: TableVerifier({
{ "*", new Vector2Verifier<T>, Optional::No, std::move(elementDocumentation) }
})
})
{}
std::string type() const override {
@@ -289,9 +320,10 @@ struct Vector2ListVerifier : public TableVerifier {
*/
template <typename T>
struct Vector3ListVerifier : public TableVerifier {
Vector3ListVerifier(std::string elementDocumentation = "") : TableVerifier({
{ "*", new Vector3Verifier<T>, Optional::No, std::move(elementDocumentation) }
})
Vector3ListVerifier(std::string elementDocumentation = "")
: TableVerifier({
{ "*", new Vector3Verifier<T>, Optional::No, std::move(elementDocumentation) }
})
{}
std::string type() const override {
@@ -305,15 +337,17 @@ struct Vector3ListVerifier : public TableVerifier {
*/
template <typename T>
struct Vector4ListVerifier : public TableVerifier {
Vector4ListVerifier(std::string elementDocumentation = "") : TableVerifier({
{ "*", new Vector4Verifier<T>, Optional::No, std::move(elementDocumentation) }
})
Vector4ListVerifier(std::string elementDocumentation = "")
: TableVerifier({
{ "*", new Vector4Verifier<T>, Optional::No, std::move(elementDocumentation) }
})
{}
std::string type() const override {
return "List of ints";
}
};
//----------------------------------------------------------------------------------------
// Matrix verifiers
//----------------------------------------------------------------------------------------
@@ -330,8 +364,7 @@ struct MatrixVerifier {};
* This Verifier checks whether the value is of type <code>glm::mat2x2<T></code>
*/
template <typename T>
struct Matrix2x2Verifier :
public TemplateVerifier<glm::tmat2x2<T>>, public MatrixVerifier
struct Matrix2x2Verifier : public TemplateVerifier<glm::tmat2x2<T>>, public MatrixVerifier
{
std::string type() const override;
};
@@ -340,8 +373,8 @@ struct Matrix2x2Verifier :
* This Verifier checks whether the value is of type <code>glm::mat2x3<T></code>
*/
template <typename T>
struct Matrix2x3Verifier :
public TemplateVerifier<glm::tmat2x3<T>>, public MatrixVerifier {
struct Matrix2x3Verifier : public TemplateVerifier<glm::tmat2x3<T>>, public MatrixVerifier
{
std::string type() const override;
};
@@ -349,8 +382,8 @@ struct Matrix2x3Verifier :
* This Verifier checks whether the value is of type <code>glm::mat2x4<T></code>
*/
template <typename T>
struct Matrix2x4Verifier :
public TemplateVerifier<glm::tmat2x4<T>>, public MatrixVerifier {
struct Matrix2x4Verifier : public TemplateVerifier<glm::tmat2x4<T>>, public MatrixVerifier
{
std::string type() const override;
};
@@ -358,8 +391,8 @@ struct Matrix2x4Verifier :
* This Verifier checks whether the value is of type <code>glm::mat3x2<T></code>
*/
template <typename T>
struct Matrix3x2Verifier :
public TemplateVerifier<glm::tmat3x2<T>>, public MatrixVerifier {
struct Matrix3x2Verifier : public TemplateVerifier<glm::tmat3x2<T>>, public MatrixVerifier
{
std::string type() const override;
};
@@ -367,8 +400,8 @@ struct Matrix3x2Verifier :
* This Verifier checks whether the value is of type <code>glm::mat3x3<T></code>
*/
template <typename T>
struct Matrix3x3Verifier :
public TemplateVerifier<glm::tmat3x3<T>>, public MatrixVerifier {
struct Matrix3x3Verifier : public TemplateVerifier<glm::tmat3x3<T>>, public MatrixVerifier
{
std::string type() const override;
};
@@ -376,8 +409,8 @@ struct Matrix3x3Verifier :
* This Verifier checks whether the value is of type <code>glm::mat3x4<T></code>
*/
template <typename T>
struct Matrix3x4Verifier :
public TemplateVerifier<glm::tmat3x4<T>>, public MatrixVerifier {
struct Matrix3x4Verifier : public TemplateVerifier<glm::tmat3x4<T>>, public MatrixVerifier
{
std::string type() const override;
};
@@ -385,8 +418,8 @@ struct Matrix3x4Verifier :
* This Verifier checks whether the value is of type <code>glm::mat4x2<T></code>
*/
template <typename T>
struct Matrix4x2Verifier :
public TemplateVerifier<glm::tmat4x2<T>>, public MatrixVerifier {
struct Matrix4x2Verifier : public TemplateVerifier<glm::tmat4x2<T>>, public MatrixVerifier
{
std::string type() const override;
};
@@ -394,8 +427,8 @@ struct Matrix4x2Verifier :
* This Verifier checks whether the value is of type <code>glm::mat4x3<T></code>
*/
template <typename T>
struct Matrix4x3Verifier :
public TemplateVerifier<glm::tmat4x3<T>>, public MatrixVerifier {
struct Matrix4x3Verifier : public TemplateVerifier<glm::tmat4x3<T>>, public MatrixVerifier
{
std::string type() const override;
};
@@ -403,8 +436,8 @@ struct Matrix4x3Verifier :
* This Verifier checks whether the value is of type <code>glm::mat4x4<T></code>
*/
template <typename T>
struct Matrix4x4Verifier :
public TemplateVerifier<glm::tmat4x4<T>>, public MatrixVerifier {
struct Matrix4x4Verifier : public TemplateVerifier<glm::tmat4x4<T>>, public MatrixVerifier
{
std::string type() const override;
};
@@ -465,18 +498,11 @@ struct OperatorVerifier : public T {
*/
template <typename T>
struct LessVerifier : public OperatorVerifier<T, std::less<typename T::Type>> {
static_assert(!std::is_base_of<BoolVerifier, T>::value, "T cannot be BoolVerifier");
static_assert(
!std::is_base_of<BoolVerifier, T>::value,
"T cannot be BoolVerifier"
);
static_assert(
!std::is_base_of<StringVerifier, T>::value,
"T cannot be StringVerifier"
);
static_assert(
!std::is_base_of<TableVerifier, T>::value,
"T cannot be TableVerifier"
!std::is_base_of<StringVerifier, T>::value, "T cannot be StringVerifier"
);
static_assert(!std::is_base_of<TableVerifier, T>::value, "T cannot be TableVerifier");
static_assert(
!std::is_base_of<VectorVerifier, T>::value,
"T cannot be VectorVerifier"
@@ -496,18 +522,12 @@ struct LessVerifier : public OperatorVerifier<T, std::less<typename T::Type>> {
*/
template <typename T>
struct LessEqualVerifier : public OperatorVerifier<T, std::less_equal<typename T::Type>> {
static_assert(
!std::is_base_of<BoolVerifier, T>::value,
"T cannot be BoolVerifier"
);
static_assert(!std::is_base_of<BoolVerifier, T>::value, "T cannot be BoolVerifier");
static_assert(
!std::is_base_of<StringVerifier, T>::value,
"T cannot be StringVerifier"
);
static_assert(
!std::is_base_of<TableVerifier, T>::value,
"T cannot be TableVerifier"
);
static_assert(!std::is_base_of<TableVerifier, T>::value, "T cannot be TableVerifier");
static_assert(
!std::is_base_of<VectorVerifier, T>::value,
"T cannot be VectorVerifier"
@@ -527,22 +547,16 @@ struct LessEqualVerifier : public OperatorVerifier<T, std::less_equal<typename T
*/
template <typename T>
struct GreaterVerifier : public OperatorVerifier<T, std::greater<typename T::Type>> {
static_assert(
!std::is_base_of<BoolVerifier, T>::value,
"T cannot be BoolVerifier"
);
static_assert(!std::is_base_of<BoolVerifier, T>::value, "T cannot be BoolVerifier");
static_assert(
!std::is_base_of<StringVerifier, T>::value,
"T cannot be StringVerifier"
);
static_assert(
!std::is_base_of<TableVerifier, T>::value,
"T cannot be TableVerifier"
);
);
static_assert(!std::is_base_of<TableVerifier, T>::value, "T cannot be TableVerifier");
static_assert(
!std::is_base_of<VectorVerifier, T>::value,
"T cannot be VectorVerifier"
);
);
using OperatorVerifier<T, std::greater<typename T::Type>>::OperatorVerifier;
@@ -560,18 +574,12 @@ template <typename T>
struct GreaterEqualVerifier : public OperatorVerifier<T,
std::greater_equal<typename T::Type>>
{
static_assert(
!std::is_base_of<BoolVerifier, T>::value,
"T cannot be BoolVerifier"
);
static_assert(!std::is_base_of<BoolVerifier, T>::value, "T cannot be BoolVerifier");
static_assert(
!std::is_base_of<StringVerifier, T>::value,
"T cannot be StringVerifier"
);
static_assert(
!std::is_base_of<TableVerifier, T>::value,
"T cannot be TableVerifier"
);
static_assert(!std::is_base_of<TableVerifier, T>::value, "T cannot be TableVerifier");
static_assert(
!std::is_base_of<VectorVerifier, T>::value,
"T cannot be VectorVerifier"

View File

@@ -86,6 +86,7 @@ public:
void touchDetectionCallback(TouchInput input);
void touchUpdateCallback(TouchInput input);
void touchExitCallback(TouchInput input);
void handleDragDrop(const std::string& file);
std::vector<std::byte> encode();
void decode(std::vector<std::byte> data);

View File

@@ -438,13 +438,11 @@ void RenderableModel::render(const RenderData& data, RendererTasks&) {
);
_program->setUniform(
_uniformCache.lightIntensities,
_lightIntensitiesBuffer.data(),
nLightSources
_lightIntensitiesBuffer
);
_program->setUniform(
_uniformCache.lightDirectionsViewSpace,
_lightDirectionsViewSpaceBuffer.data(),
nLightSources
_lightDirectionsViewSpaceBuffer
);
_program->setUniform(
_uniformCache.modelViewTransform,

View File

@@ -35,6 +35,7 @@
#include <ghoul/misc/profiling.h>
#include <ghoul/opengl/programobject.h>
#include <cmath>
#include <optional>
namespace {
constexpr const char* ProgramName = "EphemerisProgram";
@@ -144,64 +145,44 @@ namespace {
"atmospheres if needed."
};
struct [[codegen::Dictionary(RenderableTrail)]] Parameters {
// This object is used to compute locations along the path. Any Translation object
// can be used here
std::monostate translation [[codegen::reference("core_transform_translation")]];
// [[codegen::verbatim(LineColorInfo.description)]]
glm::vec3 color [[codegen::color()]];
// [[codegen::verbatim(EnableFadeInfo.description)]]
std::optional<bool> enableFade;
// [[codegen::verbatim(FadeInfo.description)]]
std::optional<float> fade;
// [[codegen::verbatim(LineWidthInfo.description)]]
std::optional<float> lineWidth;
// [[codegen::verbatim(PointSizeInfo.description)]]
std::optional<int> pointSize;
enum class RenderingMode {
Lines,
Points,
LinesPoints [[codegen::key("Lines+Points")]],
PointsLines [[codegen::key("Lines+Points")]]
};
// [[codegen::verbatim(RenderingModeInfo.description)]]
std::optional<RenderingMode> renderingMode [[codegen::key("Rendering")]];
};
#include "renderabletrail_codegen.cpp"
} // namespace
namespace openspace {
documentation::Documentation RenderableTrail::Documentation() {
using namespace documentation;
return {
"RenderableTrail",
"base_renderable_renderabletrail",
{
{
KeyTranslation,
new ReferencingVerifier("core_transform_translation"),
Optional::No,
"This object is used to compute locations along the path. Any "
"Translation object can be used here."
},
{
LineColorInfo.identifier,
new DoubleVector3Verifier,
Optional::No,
LineColorInfo.description
},
{
EnableFadeInfo.identifier,
new BoolVerifier,
Optional::Yes,
EnableFadeInfo.description
},
{
FadeInfo.identifier,
new DoubleVerifier,
Optional::Yes,
FadeInfo.description
},
{
LineWidthInfo.identifier,
new DoubleVerifier,
Optional::Yes,
LineWidthInfo.description
},
{
PointSizeInfo.identifier,
new DoubleVerifier,
Optional::Yes,
PointSizeInfo.description
},
{
RenderingModeInfo.identifier,
new StringInListVerifier(
// Taken from the RenderingModeConversion map above
{ "Lines", "Points", "Lines+Points", "Points+Lines" }
),
Optional::Yes,
RenderingModeInfo.description
}
}
};
documentation::Documentation doc = codegen::doc<Parameters>();
doc.id = "base_renderable_renderabletrail";
return doc;
}
RenderableTrail::Appearance::Appearance()
@@ -233,6 +214,8 @@ RenderableTrail::Appearance::Appearance()
RenderableTrail::RenderableTrail(const ghoul::Dictionary& dictionary)
: Renderable(dictionary)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
setRenderBin(RenderBin::Overlay);
addProperty(_opacity);
@@ -241,36 +224,25 @@ RenderableTrail::RenderableTrail(const ghoul::Dictionary& dictionary)
);
addPropertySubOwner(_translation.get());
_appearance.lineColor = dictionary.value<glm::dvec3>(LineColorInfo.identifier);
_appearance.lineColor = p.color;
_appearance.useLineFade = p.enableFade.value_or(_appearance.useLineFade);
_appearance.lineFade = p.fade.value_or(_appearance.lineFade);
_appearance.lineWidth = p.lineWidth.value_or(_appearance.lineWidth);
_appearance.pointSize = p.pointSize.value_or(_appearance.pointSize);
if (dictionary.hasValue<bool>(EnableFadeInfo.identifier)) {
_appearance.useLineFade = dictionary.value<bool>(EnableFadeInfo.identifier);
}
if (dictionary.hasValue<double>(FadeInfo.identifier)) {
_appearance.lineFade = static_cast<float>(
dictionary.value<double>(FadeInfo.identifier)
);
}
if (dictionary.hasValue<double>(LineWidthInfo.identifier)) {
_appearance.lineWidth = static_cast<float>(dictionary.value<double>(
LineWidthInfo.identifier
));
}
if (dictionary.hasValue<double>(PointSizeInfo.identifier)) {
_appearance.pointSize = static_cast<int>(
dictionary.value<double>(PointSizeInfo.identifier)
);
}
// This map is not accessed out of order as long as the Documentation is adapted
// whenever the map changes. The documentation will check for valid values
if (dictionary.hasValue<std::string>(RenderingModeInfo.identifier)) {
_appearance.renderingModes = RenderingModeConversion.at(
dictionary.value<std::string>(RenderingModeInfo.identifier)
);
if (p.renderingMode.has_value()) {
switch (*p.renderingMode) {
case Parameters::RenderingMode::Lines:
_appearance.renderingModes = RenderingModeLines;
break;
case Parameters::RenderingMode::Points:
_appearance.renderingModes = RenderingModePoints;
break;
case Parameters::RenderingMode::LinesPoints:
case Parameters::RenderingMode::PointsLines:
_appearance.renderingModes = RenderingModeLinesPoints;
break;
}
}
else {
_appearance.renderingModes = RenderingModeLines;

View File

@@ -38,11 +38,166 @@
#include "exoplanetsmodule_lua.inl"
namespace {
constexpr const openspace::properties::Property::PropertyInfo DataFolderInfo = {
"DataFolder",
"Data Folder",
"The path to the folder containing the exoplanets data and lookup table"
};
constexpr const openspace::properties::Property::PropertyInfo StarTextureInfo = {
"StarTexture",
"Star Texture",
"The path to a grayscale image that is used for the host star surfaces"
};
constexpr const openspace::properties::Property::PropertyInfo NoDataTextureInfo = {
"NoDataTexture",
"No Data Star Texture",
"A path to a texture that is used to represent that there is missing data about "
"the star. For example no color information"
};
constexpr const openspace::properties::Property::PropertyInfo OrbitDiscTextureInfo =
{
"OrbitDiscTexture",
"Orbit Disc Texture",
"A path to a 1-dimensional image used as a transfer function for the "
"exoplanets' orbit uncertainty disc"
};
constexpr const openspace::properties::Property::PropertyInfo
HabitableZoneTextureInfo =
{
"HabitableZoneTexture",
"Habitable Zone Texture",
"A path to a 1-dimensional image used as a transfer function for the "
"habitable zone disc"
};
constexpr const openspace::properties::Property::PropertyInfo
ShowComparisonCircleInfo =
{
"ShowComparisonCircle",
"Show Comparison Circle",
"If true, the 1 AU size comparison circle is enabled per default when an "
"exoplanet system is created"
};
constexpr const openspace::properties::Property::PropertyInfo
ShowHabitableZoneInfo =
{
"ShowHabitableZone",
"Show Habitable Zone",
"If true, the habitable zone disc is enabled per default when an "
"exoplanet system is created"
};
constexpr const openspace::properties::Property::PropertyInfo UseOptimisticZoneInfo =
{
"UseOptimisticZone",
"Use Optimistic Zone Boundaries",
"If true, the habitable zone is computed with optimistic boundaries per default "
"when an exoplanet system is created"
};
constexpr const char ExoplanetsDataFileName[] = "exoplanets_data.bin";
constexpr const char LookupTableFileName[] = "lookup.txt";
struct [[codegen::Dictionary(ExoplanetsModule)]] Parameters {
// [[codegen::verbatim(DataFolderInfo.description)]]
std::optional<std::string> dataFolder;
// [[codegen::verbatim(StarTextureInfo.description)]]
std::optional<std::string> starTexture;
// [[codegen::verbatim(NoDataTextureInfo.description)]]
std::optional<std::string> noDataTexture;
// [[codegen::verbatim(OrbitDiscTextureInfo.description)]]
std::optional<std::string> orbitDiscTexture;
// [[codegen::verbatim(HabitableZoneTextureInfo.description)]]
std::optional<std::string> habitableZoneTexture;
// [[codegen::verbatim(ShowComparisonCircleInfo.description)]]
std::optional<bool> showComparisonCircle;
// [[codegen::verbatim(ShowHabitableZoneInfo.description)]]
std::optional<bool> showHabitableZone;
// [[codegen::verbatim(UseOptimisticZoneInfo.description)]]
std::optional<bool> useOptimisticZone;
};
#include "exoplanetsmodule_codegen.cpp"
} // namespace
namespace openspace {
using namespace exoplanets;
ExoplanetsModule::ExoplanetsModule() : OpenSpaceModule(Name) {}
ExoplanetsModule::ExoplanetsModule()
: OpenSpaceModule(Name)
, _exoplanetsDataFolder(DataFolderInfo)
, _starTexturePath(StarTextureInfo)
, _noDataTexturePath(NoDataTextureInfo)
, _orbitDiscTexturePath(OrbitDiscTextureInfo)
, _habitableZoneTexturePath(HabitableZoneTextureInfo)
, _showComparisonCircle(ShowComparisonCircleInfo, false)
, _showHabitableZone(ShowHabitableZoneInfo, true)
, _useOptimisticZone(UseOptimisticZoneInfo, true)
{
_exoplanetsDataFolder.setReadOnly(true);
addProperty(_exoplanetsDataFolder);
addProperty(_starTexturePath);
addProperty(_noDataTexturePath);
addProperty(_orbitDiscTexturePath);
addProperty(_habitableZoneTexturePath);
addProperty(_showComparisonCircle);
addProperty(_showHabitableZone);
addProperty(_useOptimisticZone);
}
std::string ExoplanetsModule::exoplanetsDataPath() const {
return absPath(
fmt::format("{}/{}", _exoplanetsDataFolder, ExoplanetsDataFileName)
);
};
std::string ExoplanetsModule::lookUpTablePath() const {
return absPath(
fmt::format("{}/{}", _exoplanetsDataFolder, LookupTableFileName)
);
};
std::string ExoplanetsModule::starTexturePath() const {
return _starTexturePath;
}
std::string ExoplanetsModule::noDataTexturePath() const {
return _noDataTexturePath;
}
std::string ExoplanetsModule::orbitDiscTexturePath() const {
return _orbitDiscTexturePath;
}
std::string ExoplanetsModule::habitableZoneTexturePath() const {
return _habitableZoneTexturePath;
}
bool ExoplanetsModule::showComparisonCircle() const {
return _showComparisonCircle;
}
bool ExoplanetsModule::showHabitableZone() const {
return _showHabitableZone;
}
bool ExoplanetsModule::useOptimisticZone() const {
return _useOptimisticZone;
}
scripting::LuaLibrary ExoplanetsModule::luaLibrary() const {
scripting::LuaLibrary res;
@@ -83,7 +238,18 @@ scripting::LuaLibrary ExoplanetsModule::luaLibrary() const {
return res;
}
void ExoplanetsModule::internalInitialize(const ghoul::Dictionary&) {
void ExoplanetsModule::internalInitialize(const ghoul::Dictionary& dict) {
const Parameters p = codegen::bake<Parameters>(dict);
_exoplanetsDataFolder = p.dataFolder.value_or(_exoplanetsDataFolder);
_starTexturePath = p.starTexture.value_or(_starTexturePath);
_noDataTexturePath = p.noDataTexture.value_or(_noDataTexturePath);
_orbitDiscTexturePath = p.orbitDiscTexture.value_or(_orbitDiscTexturePath);
_habitableZoneTexturePath = p.habitableZoneTexture.value_or(_habitableZoneTexturePath);
_showComparisonCircle = p.showComparisonCircle.value_or(_showComparisonCircle);
_showHabitableZone = p.showHabitableZone.value_or(_showHabitableZone);
_useOptimisticZone = p.useOptimisticZone.value_or(_useOptimisticZone);
auto fTask = FactoryManager::ref().factory<Task>();
auto fRenderable = FactoryManager::ref().factory<Renderable>();
ghoul_assert(fTask, "No task factory existed");

View File

@@ -28,6 +28,8 @@
#include <openspace/util/openspacemodule.h>
#include <openspace/documentation/documentation.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/stringproperty.h>
namespace openspace {
@@ -38,11 +40,30 @@ public:
ExoplanetsModule();
virtual ~ExoplanetsModule() = default;
std::string exoplanetsDataPath() const;
std::string lookUpTablePath() const;
std::string starTexturePath() const;
std::string noDataTexturePath() const;
std::string orbitDiscTexturePath() const;
std::string habitableZoneTexturePath() const;
bool showComparisonCircle() const;
bool showHabitableZone() const;
bool useOptimisticZone() const;
scripting::LuaLibrary luaLibrary() const override;
std::vector<documentation::Documentation> documentations() const override;
protected:
void internalInitialize(const ghoul::Dictionary&) override;
void internalInitialize(const ghoul::Dictionary& dict) override;
properties::StringProperty _exoplanetsDataFolder;
properties::StringProperty _starTexturePath;
properties::StringProperty _noDataTexturePath;
properties::StringProperty _orbitDiscTexturePath;
properties::StringProperty _habitableZoneTexturePath;
properties::BoolProperty _showComparisonCircle;
properties::BoolProperty _showHabitableZone;
properties::BoolProperty _useOptimisticZone;
};
} // namespace openspace

View File

@@ -24,6 +24,7 @@
#include <modules/exoplanets/exoplanetshelper.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scripting/scriptengine.h>
@@ -40,47 +41,42 @@
namespace {
constexpr const char _loggerCat[] = "ExoplanetsModule";
constexpr const char ExoplanetsGuiPath[] = "/Milky Way/Exoplanets/Exoplanet Systems/";
// Lua cannot handle backslashes, so replace these with forward slashes
std::string formatPathToLua(const std::string& path) {
std::string resPath = path;
std::replace(resPath.begin(), resPath.end(), '\\', '/');
return resPath;
}
} // namespace
namespace openspace::exoplanets::luascriptfunctions {
constexpr const char ExoplanetsGuiPath[] = "/Milky Way/Exoplanets/Exoplanet Systems/";
constexpr const char LookUpTablePath[] = "${SYNC}/http/exoplanets_data/2/lookup.txt";
constexpr const char ExoplanetsDataPath[] =
"${SYNC}/http/exoplanets_data/2/exoplanets_data.bin";
constexpr const char StarTextureFile[] = "${SYNC}/http/exoplanets_textures/2/sun.jpg";
constexpr const char NoDataTextureFile[] =
"${SYNC}/http/exoplanets_textures/2/grid-32.png";
constexpr const char DiscTextureFile[] =
"${SYNC}/http/exoplanets_textures/2/disc_bw_texture.png";
constexpr const char HabitableZoneTextureFile[] =
"${SYNC}/http/habitable_zone_textures/1/hot_to_cold_faded.png";
constexpr const float AU = static_cast<float>(distanceconstants::AstronomicalUnit);
constexpr const float SolarRadius = static_cast<float>(distanceconstants::SolarRadius);
constexpr const float JupiterRadius = static_cast<float>(distanceconstants::JupiterRadius);
ExoplanetSystem findExoplanetSystemInData(std::string_view starName) {
ExoplanetSystem system;
const ExoplanetsModule* module = global::moduleEngine->module<ExoplanetsModule>();
std::ifstream data(absPath(ExoplanetsDataPath), std::ios::in | std::ios::binary);
const std::string binPath = module->exoplanetsDataPath();
std::ifstream data(absPath(binPath), std::ios::in | std::ios::binary);
if (!data.good()) {
LERROR(fmt::format(
"Failed to open exoplanets data file: '{}'", absPath(ExoplanetsDataPath)
));
LERROR(fmt::format("Failed to open exoplanets data file: '{}'", binPath));
return ExoplanetSystem();
}
std::ifstream lut(absPath(LookUpTablePath));
const std::string lutPath = module->lookUpTablePath();
std::ifstream lut(absPath(lutPath));
if (!lut.good()) {
LERROR(fmt::format(
"Failed to open exoplanets look-up table: '{}'", absPath(LookUpTablePath)
));
LERROR(fmt::format("Failed to open exoplanets look-up table: '{}'", lutPath));
return ExoplanetSystem();
}
ExoplanetSystem system;
// 1. search lut for the starname and return the corresponding location
// 2. go to that location in the data file
// 3. read sizeof(exoplanet) bytes into an exoplanet object.
@@ -167,6 +163,8 @@ void createExoplanetSystem(const std::string& starName) {
return;
}
const ExoplanetsModule* module = global::moduleEngine->module<ExoplanetsModule>();
const glm::dvec3 starPos =
static_cast<glm::dvec3>(starPosInParsec) * distanceconstants::Parsec;
const glm::dmat3 exoplanetSystemRotation = computeSystemRotation(starPos);
@@ -182,6 +180,7 @@ void createExoplanetSystem(const std::string& starName) {
if (!std::isnan(bv)) {
const glm::vec3 color = starColor(bv);
const std::string starTexture = module->starTexturePath();
colorLayers =
"{"
"Identifier = 'StarColor',"
@@ -192,18 +191,17 @@ void createExoplanetSystem(const std::string& starName) {
"},"
"{"
"Identifier = 'StarTexture',"
"FilePath = " +
fmt::format("openspace.absPath('{}')", StarTextureFile) + ","
"FilePath = openspace.absPath('" + formatPathToLua(starTexture) + "'),"
"BlendMode = 'Color',"
"Enabled = true"
"}";
}
else {
const std::string noDataTexture = module->noDataTexturePath();
colorLayers =
"{"
"Identifier = 'NoDataStarTexture',"
"FilePath = " +
fmt::format("openspace.absPath('{}')", NoDataTextureFile) + ","
"FilePath = openspace.absPath('" + formatPathToLua(noDataTexture) + "'),"
"BlendMode = 'Color',"
"Enabled = true"
"}";
@@ -313,7 +311,6 @@ void createExoplanetSystem(const std::string& starName) {
const std::string planetNode = "{"
"Identifier = '" + planetIdentifier + "',"
"Parent = '" + starIdentifier + "',"
"Enabled = true,"
"Renderable = {"
"Type = 'RenderableGlobe',"
"Enabled = " + enabled + ","
@@ -342,7 +339,6 @@ void createExoplanetSystem(const std::string& starName) {
const std::string planetTrailNode = "{"
"Identifier = '" + planetIdentifier + "_Trail',"
"Parent = '" + starIdentifier + "',"
"Enabled = true,"
"Renderable = {"
"Type = 'RenderableTrailOrbit',"
"Period = " + std::to_string(planet.per) + ","
@@ -376,13 +372,16 @@ void createExoplanetSystem(const std::string& starName) {
const float lowerOffset = static_cast<float>(planet.aLower / planet.a);
const float upperOffset = static_cast<float>(planet.aUpper / planet.a);
const std::string discTexture = module->orbitDiscTexturePath();
const std::string discNode = "{"
"Identifier = '" + planetIdentifier + "_Disc',"
"Parent = '" + starIdentifier + "',"
"Enabled = true,"
"Renderable = {"
"Type = 'RenderableOrbitDisc',"
"Texture = openspace.absPath('" + DiscTextureFile + "'),"
"Texture = openspace.absPath('" +
formatPathToLua(discTexture) +
"'),"
"Size = " + std::to_string(semiMajorAxisInMeter) + ","
"Eccentricity = " + std::to_string(planet.ecc) + ","
"Offset = { " +
@@ -410,7 +409,6 @@ void createExoplanetSystem(const std::string& starName) {
}
}
float meanInclination = 0.f;
for (const ExoplanetDataEntry& p : system.planetsData) {
meanInclination += p.i;
@@ -419,14 +417,16 @@ void createExoplanetSystem(const std::string& starName) {
const glm::dmat4 rotation = computeOrbitPlaneRotationMatrix(meanInclination);
const glm::dmat3 meanOrbitPlaneRotationMatrix = static_cast<glm::dmat3>(rotation);
// 1 AU Size Comparison Ring
const std::string ringIdentifier = starIdentifier + "_1AU_Ring";
const std::string ring = "{"
"Identifier = '" + starIdentifier + "_1AU_Ring',"
bool isCircleEnabled = module->showComparisonCircle();
const std::string isCircleEnabledString = isCircleEnabled ? "true" : "false";
// 1 AU Size Comparison Circle
const std::string circle = "{"
"Identifier = '" + starIdentifier + "_1AU_Circle',"
"Parent = '" + starIdentifier + "',"
"Enabled = false,"
"Renderable = {"
"Type = 'RenderableRadialGrid',"
"Enabled = " + isCircleEnabledString + ","
"OuterRadius = " + std::to_string(AU) + ","
"CircleSegments = 64,"
"LineWidth = 2.0,"
@@ -438,13 +438,13 @@ void createExoplanetSystem(const std::string& starName) {
"}"
"},"
"GUI = {"
"Name = '1 AU Size Comparison Ring',"
"Name = '1 AU Size Comparison Circle',"
"Path = '" + guiPath + "'"
"}"
"}";
openspace::global::scriptEngine->queueScript(
"openspace.addSceneGraphNode(" + ring + ");",
"openspace.addSceneGraphNode(" + circle + ");",
scripting::ScriptEngine::RemoteScripting::Yes
);
@@ -463,16 +463,24 @@ void createExoplanetSystem(const std::string& starName) {
"the greenhouse effect would not be able to maintain surface temperature "
"above freezing anywhere on the planet.";
const std::string hzTexture = module->habitableZoneTexturePath();
bool isHzEnabled = module->showHabitableZone();
const std::string isHzEnabledString = isHzEnabled ? "true" : "false";
bool useOptimistic = module->useOptimisticZone();
const std::string useOptimisticString = useOptimistic ? "true" : "false";
const std::string zoneDiscNode = "{"
"Identifier = '" + starIdentifier + "_HZ_Disc',"
"Parent = '" + starIdentifier + "',"
"Enabled = true,"
"Renderable = {"
"Type = 'RenderableHabitableZone',"
"Texture = openspace.absPath('" + HabitableZoneTextureFile + "'),"
"Enabled = " + isHzEnabledString + ","
"Texture = openspace.absPath('" + formatPathToLua(hzTexture) + "'),"
"Luminosity = " + std::to_string(system.starData.luminosity) + ","
"EffectiveTemperature = " + std::to_string(system.starData.teff) + ","
"Optimistic = true,"
"Optimistic = " + useOptimisticString + ","
"Opacity = 0.07"
"},"
"Transform = {"
@@ -545,21 +553,25 @@ int removeExoplanetSystem(lua_State* L) {
}
std::vector<std::string> hostStarsWithSufficientData() {
const ExoplanetsModule* module = global::moduleEngine->module<ExoplanetsModule>();
const std::string lutPath = module->lookUpTablePath();
std::ifstream lookupTableFile(absPath(lutPath));
if (!lookupTableFile.good()) {
LERROR(fmt::format("Failed to open lookup table file '{}'", lutPath));
return {};
}
const std::string binPath = module->exoplanetsDataPath();
std::ifstream data(absPath(binPath), std::ios::in | std::ios::binary);
if (!data.good()) {
LERROR(fmt::format("Failed to open data file '{}'", binPath));
return {};
}
std::vector<std::string> names;
std::string line;
std::ifstream lookupTableFile(absPath(LookUpTablePath));
if (!lookupTableFile.good()) {
LERROR(fmt::format("Failed to open lookup table file '{}'", LookUpTablePath));
return {};
}
std::ifstream data(absPath(ExoplanetsDataPath), std::ios::in | std::ios::binary);
if (!data.good()) {
LERROR(fmt::format("Failed to open data file '{}'", ExoplanetsDataPath));
return {};
}
// Read number of lines
int nExoplanets = 0;
while (std::getline(lookupTableFile, line)) {

View File

@@ -45,6 +45,7 @@
#include <vector>
namespace {
constexpr const char* _loggerCat = "OrbitalKepler";
constexpr const char* ProgramName = "OrbitalKepler";
// Fragile! Keep in sync with documentation
@@ -114,62 +115,6 @@ namespace {
LeapSecond{ 2017, 1 }
};
static const openspace::properties::Property::PropertyInfo PathInfo = {
"Path",
"Path",
"The file path to the data file to read"
};
static const openspace::properties::Property::PropertyInfo SegmentQualityInfo = {
"SegmentQuality",
"Segment Quality",
"A segment quality value for the orbital trail. A value from 1 (lowest) to "
"10 (highest) that controls the number of line segments in the rendering of the "
"orbital trail. This does not control the direct number of segments because "
"these automatically increase according to the eccentricity of the orbit."
};
constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = {
"LineWidth",
"Line Width",
"This value specifies the line width of the trail if the selected rendering "
"method includes lines. If the rendering mode is set to Points, this value is "
"ignored."
};
constexpr openspace::properties::Property::PropertyInfo LineColorInfo = {
"Color",
"Color",
"This value determines the RGB main color for the lines and points of the trail."
};
constexpr openspace::properties::Property::PropertyInfo TrailFadeInfo = {
"TrailFade",
"Trail Fade",
"This value determines how fast the trail fades and is an appearance property. "
};
static const openspace::properties::Property::PropertyInfo UpperLimitInfo = {
"UpperLimit",
"Upper Limit",
"Upper limit on the number of objects for this renderable, regardless of "
"how many objects are contained in the data file. Produces an evenly-distributed"
"sample from the data file."
};
static const openspace::properties::Property::PropertyInfo StartRenderIdxInfo = {
"StartRenderIdx",
"Starting Index of Render",
"Index of object in renderable group to start rendering (all prior objects will "
"be ignored)."
};
static const openspace::properties::Property::PropertyInfo RenderSizeInfo = {
"RenderSizeInfo",
"Size of Render Block",
"Number of objects to render sequentially from StartRenderIdx"
};
constexpr openspace::properties::Property::PropertyInfo RenderBinModeInfo = {
"RenderBinMode",
"RenderBin Mode",
"Determines if the trails will be rendered after all other elements, including"
"atmospheres if needed."
};
// Count the number of full days since the beginning of 2000 to the beginning of
// the parameter 'year'
int countDays(int year) {
@@ -238,10 +183,90 @@ namespace {
return dayCount;
}
static const openspace::properties::Property::PropertyInfo PathInfo = {
"Path",
"Path",
"The file path to the data file to read"
};
static const openspace::properties::Property::PropertyInfo SegmentQualityInfo = {
"SegmentQuality",
"Segment Quality",
"A segment quality value for the orbital trail. A value from 1 (lowest) to "
"10 (highest) that controls the number of line segments in the rendering of the "
"orbital trail. This does not control the direct number of segments because "
"these automatically increase according to the eccentricity of the orbit."
};
constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = {
"LineWidth",
"Line Width",
"This value specifies the line width of the trail if the selected rendering "
"method includes lines. If the rendering mode is set to Points, this value is "
"ignored."
};
constexpr openspace::properties::Property::PropertyInfo LineColorInfo = {
"Color",
"Color",
"This value determines the RGB main color for the lines and points of the trail."
};
constexpr openspace::properties::Property::PropertyInfo TrailFadeInfo = {
"TrailFade",
"Trail Fade",
"This value determines how fast the trail fades and is an appearance property. "
};
static const openspace::properties::Property::PropertyInfo StartRenderIdxInfo = {
"StartRenderIdx",
"Contiguous Starting Index of Render",
"Index of object in renderable group to start rendering (all prior objects will "
"be ignored)."
};
static const openspace::properties::Property::PropertyInfo RenderSizeInfo = {
"RenderSize",
"Contiguous Size of Render Block",
"Number of objects to render sequentially from StartRenderIdx"
};
constexpr openspace::properties::Property::PropertyInfo RenderBinModeInfo = {
"RenderBinMode",
"RenderBin Mode",
"Determines if the trails will be rendered after all other elements, including"
"atmospheres if needed."
};
struct [[codegen::Dictionary(RenderableOrbitalKepler)]] Parameters {
// [[codegen::verbatim(PathInfo.description)]]
std::string path;
// [[codegen::verbatim(SegmentQualityInfo.description)]]
double segmentQuality;
// [[codegen::verbatim(LineWidthInfo.description)]]
std::optional<double> lineWidth;
// [[codegen::verbatim(LineColorInfo.description)]]
glm::dvec3 color;
// [[codegen::verbatim(TrailFadeInfo.description)]]
std::optional<double> trailFade;
// [[codegen::verbatim(StartRenderIdxInfo.description)]]
std::optional<int> startRenderIdx;
// [[codegen::verbatim(RenderSizeInfo.description)]]
std::optional<int> renderSize;
// [[codegen::verbatim(RenderBinModeInfo.description)]]
std::optional<std::string> renderBinMode;
};
#include "renderableorbitalkepler_codegen.cpp"
} // namespace
namespace openspace {
documentation::Documentation RenderableOrbitalKepler::Documentation() {
documentation::Documentation doc = codegen::doc<Parameters>();
doc.id = "space_renderableorbitalkepler";
return doc;
}
double RenderableOrbitalKepler::calculateSemiMajorAxis(double meanMotion) const {
constexpr const double GravitationalConstant = 6.6740831e-11;
constexpr const double MassEarth = 5.9721986e24;
@@ -363,7 +388,6 @@ double RenderableOrbitalKepler::epochFromYMDdSubstring(const std::string& epochS
RenderableOrbitalKepler::RenderableOrbitalKepler(const ghoul::Dictionary& dict)
: Renderable(dict)
, _upperLimit(UpperLimitInfo, 1000, 1, 1000000)
, _segmentQuality(SegmentQualityInfo, 2, 1, 10)
, _startRenderIdx(StartRenderIdxInfo, 0, 0, 1)
, _sizeRender(RenderSizeInfo, 1, 1, 2)
@@ -374,7 +398,6 @@ RenderableOrbitalKepler::RenderableOrbitalKepler(const ghoul::Dictionary& dict)
dict,
"RenderableOrbitalKepler"
);
_path = dict.value<std::string>(PathInfo.identifier);
_segmentQuality = static_cast<int>(dict.value<double>(SegmentQualityInfo.identifier));
@@ -387,20 +410,21 @@ RenderableOrbitalKepler::RenderableOrbitalKepler(const ghoul::Dictionary& dict)
static_cast<float>(dict.value<double>(TrailFadeInfo.identifier)) :
20.f;
_upperLimit =
dict.hasValue<double>(UpperLimitInfo.identifier) ?
static_cast<unsigned int>(dict.value<double>(UpperLimitInfo.identifier)) :
0u;
if (dict.hasValue<double>(StartRenderIdxInfo.identifier)) {
_startRenderIdx = static_cast<unsigned int>(
dict.value<double>(StartRenderIdxInfo.identifier));
}
else {
_startRenderIdx = 0u;
}
_startRenderIdx =
dict.hasValue<double>(StartRenderIdxInfo.identifier) ?
static_cast<unsigned int>(dict.value<double>(StartRenderIdxInfo.identifier)) :
0u;
_sizeRender =
dict.hasValue<double>(RenderSizeInfo.identifier) ?
static_cast<unsigned int>(dict.value<double>(RenderSizeInfo.identifier)) :
0u;
if (dict.hasValue<double>(RenderSizeInfo.identifier)) {
_sizeRender = static_cast<unsigned int>(
dict.value<double>(RenderSizeInfo.identifier));
}
else {
_sizeRender = 0u;
}
_appearance.lineWidth =
dict.hasValue<double>(LineWidthInfo.identifier) ?
@@ -415,13 +439,6 @@ RenderableOrbitalKepler::RenderableOrbitalKepler(const ghoul::Dictionary& dict)
addProperty(_path);
addProperty(_segmentQuality);
addProperty(_opacity);
addProperty(_startRenderIdx);
addProperty(_sizeRender);
_updateStartRenderIdxSelect = std::function<void()>([this] { initializeGL(); });
_updateRenderSizeSelect = std::function<void()>([this] { initializeGL(); });
_startRenderIdxCallbackHandle = _startRenderIdx.onChange(_updateStartRenderIdxSelect);
_sizeRenderCallbackHandle = _sizeRender.onChange(_updateRenderSizeSelect);
if (dict.hasValue<std::string>(RenderBinModeInfo.identifier)) {
Renderable::RenderBin cfgRenderBin = RenderBinConversion.at(
@@ -435,6 +452,8 @@ RenderableOrbitalKepler::RenderableOrbitalKepler(const ghoul::Dictionary& dict)
}
void RenderableOrbitalKepler::initializeGL() {
ghoul_assert(_vertexArray == 0, "Vertex array object already existed");
ghoul_assert(_vertexBuffer == 0, "Vertex buffer object already existed");
glGenVertexArrays(1, &_vertexArray);
glGenBuffers(1, &_vertexBuffer);
@@ -481,6 +500,11 @@ void RenderableOrbitalKepler::render(const RenderData& data, RendererTasks&) {
return;
}
if (_updateDataBuffersAtNextRender) {
_updateDataBuffersAtNextRender = false;
initializeGL();
}
_programObject->activate();
_programObject->setUniform(_uniformCache.opacity, _opacity);
_programObject->setUniform(_uniformCache.inGameTime, data.time.j2000Seconds());

View File

@@ -37,6 +37,8 @@
namespace openspace {
namespace documentation { struct Documentation; }
class RenderableOrbitalKepler : public Renderable {
public:
RenderableOrbitalKepler(const ghoul::Dictionary& dictionary);
@@ -62,9 +64,12 @@ public:
virtual void readDataFile(const std::string& filename) = 0;
protected:
static documentation::Documentation Documentation();
double calculateSemiMajorAxis(double meanMotion) const;
double epochFromSubstring(const std::string& epochString) const;
double epochFromYMDdSubstring(const std::string& epochString);
void updateBuffers();
std::function<void()> _reinitializeTrailBuffers;
std::function<void()> _updateStartRenderIdxSelect;
@@ -81,15 +86,15 @@ protected:
double epoch = 0.0;
double period = 0.0;
};
bool _updateDataBuffersAtNextRender = false;
std::streamoff _numObjects;
bool _isFileReadinitialized = false;
inline static constexpr double convertAuToKm = 1.496e8;
inline static constexpr double convertDaysToSecs = 86400.0;
std::vector<KeplerParameters> _data;
std::vector<size_t> _segmentSize;
properties::UIntProperty _upperLimit;
properties::UIntProperty _segmentQuality;
properties::Property::OnChangeHandle _upperLimitCallbackHandle;
properties::UIntProperty _startRenderIdx;
properties::UIntProperty _sizeRender;
properties::Property::OnChangeHandle _startRenderIdxCallbackHandle;
@@ -121,7 +126,6 @@ private:
GLuint _vertexArray;
GLuint _vertexBuffer;
void updateBuffers();
ghoul::opengl::ProgramObject* _programObject;
properties::StringProperty _path;

View File

@@ -47,49 +47,15 @@
namespace {
constexpr const char* _loggerCat = "Satellites";
static const openspace::properties::Property::PropertyInfo PathInfo = {
"Path",
"Path",
"The file path to the TLE file to read"
};
static const openspace::properties::Property::PropertyInfo SegmentsInfo = {
"Segments",
"Segments",
"The number of segments to use for each orbit ellipse"
};
constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = {
"LineWidth",
"Line Width",
"This value specifies the line width of the trail if the selected rendering "
"method includes lines. If the rendering mode is set to Points, this value is "
"ignored."
};
constexpr openspace::properties::Property::PropertyInfo LineColorInfo = {
"Color",
"Color",
"This value determines the RGB main color for the lines and points of the trail."
};
constexpr openspace::properties::Property::PropertyInfo TrailFadeInfo = {
"TrailFade",
"Trail Fade",
"This value determines how fast the trail fades and is an appearance property. "
};
struct [[codegen::Dictionary(RenderableSatellites)]] Parameters {
// [[codegen::verbatim(SegmentsInfo.description)]]
double segments;
// [[codegen::verbatim(PathInfo.description)]]
std::string path;
// [[codegen::verbatim(LineWidthInfo.description)]]
std::optional<double> lineWidth;
// [[codegen::verbatim(LineColorInfo.description)]]
glm::dvec3 color;
// [[codegen::verbatim(TrailFadeInfo.description)]]
std::optional<double> trailFade;
};
#include "renderablesatellites_codegen.cpp"
}
@@ -98,7 +64,17 @@ namespace openspace {
documentation::Documentation RenderableSatellites::Documentation() {
documentation::Documentation doc = codegen::doc<Parameters>();
doc.id = "space_renderable_satellites";
doc.id = "space_renderablesatellites";
// Insert the parents documentation entries until we have a verifier that can deal
// with class hierarchy
documentation::Documentation parentDoc = RenderableOrbitalKepler::Documentation();
doc.entries.insert(
doc.entries.end(),
parentDoc.entries.begin(),
parentDoc.entries.end()
);
return doc;
}
@@ -109,12 +85,29 @@ RenderableSatellites::RenderableSatellites(const ghoul::Dictionary& dictionary)
// probably want a codegen::check function that only does the checking without
// actually creating a Parameter objects
// codegen::bake<Parameters>(dictionary);
addProperty(_startRenderIdx);
addProperty(_sizeRender);
_updateStartRenderIdxSelect = [this]() {
if ((_numObjects - _startRenderIdx) < _sizeRender) {
_sizeRender = _numObjects - _startRenderIdx;
}
updateBuffers();
};
_updateRenderSizeSelect = [this]() {
if (_sizeRender > (_numObjects - _startRenderIdx)) {
_startRenderIdx = _numObjects - _sizeRender;
}
updateBuffers();
};
_startRenderIdxCallbackHandle = _startRenderIdx.onChange(_updateStartRenderIdxSelect);
_sizeRenderCallbackHandle = _sizeRender.onChange(_updateRenderSizeSelect);
}
void RenderableSatellites::readDataFile(const std::string& filename) {
if (!FileSys.fileExists(filename)) {
throw ghoul::RuntimeError(fmt::format(
"Satellite TLE file {} does not exist.", filename
"Satellite TLE file {} does not exist", filename
));
}
_data.clear();
@@ -162,7 +155,7 @@ void RenderableSatellites::readDataFile(const std::string& filename) {
// 5 12-14 International Designator (Launch number of the year)
// 6 15-17 International Designator(piece of the launch) A
name += " " + line.substr(2, 15);
if (_startRenderIdx > 0 && _startRenderIdx == i) {
if (_startRenderIdx == i && _sizeRender == 1) {
LINFO(fmt::format(
"Set render block to start at object {}",
name
@@ -251,16 +244,11 @@ void RenderableSatellites::readDataFile(const std::string& filename) {
}
void RenderableSatellites::initializeFileReading() {
_startRenderIdx.removeOnChange(_startRenderIdxCallbackHandle);
_sizeRender.removeOnChange(_sizeRenderCallbackHandle);
_startRenderIdx.setMaxValue(static_cast<unsigned int>(_numObjects - 1));
_sizeRender.setMaxValue(static_cast<unsigned int>(_numObjects));
_startRenderIdx = static_cast<unsigned int>(0);
_sizeRender = static_cast<unsigned int>(_numObjects);
_startRenderIdxCallbackHandle = _startRenderIdx.onChange(
_updateStartRenderIdxSelect);
_sizeRenderCallbackHandle = _sizeRender.onChange(
_updateRenderSizeSelect);
if (_sizeRender == 0u) {
_sizeRender = static_cast<unsigned int>(_numObjects);
}
}
void RenderableSatellites::skipSingleEntryInFile(std::ifstream& file) {

View File

@@ -38,6 +38,8 @@
namespace openspace {
namespace documentation { struct Documentation; }
class RenderableSatellites : public RenderableOrbitalKepler {
public:
RenderableSatellites(const ghoul::Dictionary& dictionary);

View File

@@ -48,41 +48,20 @@
namespace {
constexpr const char* _loggerCat = "SmallSolarSystemBody";
static const openspace::properties::Property::PropertyInfo PathInfo = {
"Path",
"Path",
"The file path to the SBDB .csv file to read"
};
static const openspace::properties::Property::PropertyInfo SegmentQualityInfo = {
"SegmentQuality",
"Segment Quality",
"A segment quality value for the orbital trail. A value from 1 (lowest) to "
"100 (highest) that controls the number of line segments in the rendering of the "
"orbital trail. This does not control the direct number of segments because "
"these automatically increase according to the eccentricity of the orbit."
};
constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = {
"LineWidth",
"Line Width",
"This value specifies the line width of the trail if the selected rendering "
"method includes lines. If the rendering mode is set to Points, this value is "
"ignored."
};
constexpr openspace::properties::Property::PropertyInfo LineColorInfo = {
"Color",
"Color",
"This value determines the RGB main color for the lines and points of the trail."
};
constexpr openspace::properties::Property::PropertyInfo TrailFadeInfo = {
"TrailFade",
"Trail Fade",
"This value determines how fast the trail fades and is an appearance property. "
static const openspace::properties::Property::PropertyInfo ContiguousModeInfo = {
"ContiguousMode",
"Contiguous Mode",
"If enabled, then the contiguous set of objects starting from StartRenderIdx "
"of size RenderSize will be rendered. If disabled, then the number of objects "
"defined by UpperLimit will rendered from an evenly dispersed sample of the "
"full length of the data file."
};
static const openspace::properties::Property::PropertyInfo UpperLimitInfo = {
"UpperLimit",
"Upper Limit",
"Upper limit on the number of objects for this renderable, regardless of "
"how many objects are contained in the data file"
"how many objects are contained in the data file. Produces an evenly-distributed"
"sample from the data file."
};
double importAngleValue(const std::string& angle) {
@@ -106,23 +85,11 @@ namespace {
}
struct [[codegen::Dictionary(RenderableSmallBody)]] Parameters {
// [[codegen::verbatim(SegmentQualityInfo.description)]]
double segmentQuality;
// [[codegen::verbatim(ContiguousModeInfo.description)]]
std::optional<bool> contiguousMode;
// [[codegen::verbatim(UpperLimitInfo.description)]]
std::optional<int> upperLimit;
// [[codegen::verbatim(PathInfo.description)]]
std::string path;
// [[codegen::verbatim(LineWidthInfo.description)]]
std::optional<double> lineWidth;
// [[codegen::verbatim(LineColorInfo.description)]]
glm::dvec3 color;
// [[codegen::verbatim(TrailFadeInfo.description)]]
std::optional<double> trailFade;
};
#include "renderablesmallbody_codegen.cpp"
} // namespace
@@ -131,17 +98,77 @@ namespace openspace {
documentation::Documentation RenderableSmallBody::Documentation() {
documentation::Documentation doc = codegen::doc<Parameters>();
doc.id = "space_renderable_small_body";
doc.id = "space_renderablesmallbody";
// Insert the parents documentation entries until we have a verifier that can deal
// with class hierarchy
documentation::Documentation parentDoc = RenderableOrbitalKepler::Documentation();
doc.entries.insert(
doc.entries.end(),
parentDoc.entries.begin(),
parentDoc.entries.end()
);
return doc;
}
RenderableSmallBody::RenderableSmallBody(const ghoul::Dictionary& dictionary)
: RenderableOrbitalKepler(dictionary)
, _upperLimit(UpperLimitInfo, 1000, 1, 1000000)
, _contiguousMode(ContiguousModeInfo, false)
{
codegen::bake<Parameters>(dictionary);
_upperLimitCallbackHandle = _upperLimit.onChange(_reinitializeTrailBuffers);
addProperty(_startRenderIdx);
addProperty(_sizeRender);
addProperty(_contiguousMode);
addProperty(_upperLimit);
if (dictionary.hasValue<double>(UpperLimitInfo.identifier)) {
_upperLimit = static_cast<unsigned int>(
dictionary.value<double>(UpperLimitInfo.identifier));
}
else {
_upperLimit = 0u;
}
if (dictionary.hasValue<bool>(ContiguousModeInfo.identifier)) {
_contiguousMode = static_cast<bool>(
dictionary.value<bool>(ContiguousModeInfo.identifier));
}
else {
_contiguousMode = false;
}
_updateStartRenderIdxSelect = std::function<void()>([this] {
if (_contiguousMode) {
if ((_numObjects - _startRenderIdx) < _sizeRender) {
_sizeRender = _numObjects - _startRenderIdx;
}
_updateDataBuffersAtNextRender = true;
}
});
_updateRenderSizeSelect = std::function<void()>([this] {
if (_contiguousMode) {
if (_sizeRender > (_numObjects - _startRenderIdx)) {
_startRenderIdx = _numObjects - _sizeRender;
}
_updateDataBuffersAtNextRender = true;
}
});
_updateRenderUpperLimitSelect = std::function<void()>([this] {
if (!_contiguousMode) {
_updateDataBuffersAtNextRender = true;
}
});
_updateContiguousModeSelect = std::function<void()>([this] {
_updateDataBuffersAtNextRender = true;
});
_startRenderIdxCallbackHandle = _startRenderIdx.onChange(_updateStartRenderIdxSelect);
_sizeRenderCallbackHandle = _sizeRender.onChange(_updateRenderSizeSelect);
_upperLimitCallbackHandle = _upperLimit.onChange(_updateRenderUpperLimitSelect);
_contiguousModeCallbackhandle =
_contiguousMode.onChange(_updateContiguousModeSelect);
}
void RenderableSmallBody::readDataFile(const std::string& filename) {
@@ -183,14 +210,18 @@ void RenderableSmallBody::readDataFile(const std::string& filename) {
_isFileReadinitialized = true;
initializeFileReading();
}
unsigned int startElement = 0;
unsigned int endElement;
if (_contiguousMode) {
lineSkipFraction = 1.0;
startElement = _startRenderIdx;
endElement = _startRenderIdx + _sizeRender - 1;
}
else {
if (_sizeRender < _numObjects || _startRenderIdx > 0) {
lineSkipFraction = 1.0;
}
else {
lineSkipFraction = static_cast<float>(_upperLimit)
/ static_cast<float>(_numObjects);
}
lineSkipFraction = static_cast<float>(_upperLimit)
/ static_cast<float>(_numObjects);
endElement = _numObjects - 1;
}
if (line.compare(expectedHeaderLine) != 0) {
@@ -202,18 +233,17 @@ void RenderableSmallBody::readDataFile(const std::string& filename) {
}
unsigned int sequentialLineErrors = 0;
unsigned int endElement = _startRenderIdx + _sizeRender - 1;
endElement =
(endElement >= _numObjects) ?
static_cast<unsigned int>(_numObjects - 1) :
endElement;
// Burn lines if not starting at first element
for (unsigned int k = 0; k < _startRenderIdx; ++k) {
for (unsigned int k = 0; k < startElement; ++k) {
skipSingleLineInFile(file);
}
bool firstDataLine = true;
int lastLineCount = -1;
for (csvLine = _startRenderIdx + 1;
for (csvLine = startElement + 1;
csvLine <= endElement + 1;
csvLine++, sequentialLineErrors++)
{
@@ -272,20 +302,16 @@ void RenderableSmallBody::readDataFile(const std::string& filename) {
}
void RenderableSmallBody::initializeFileReading() {
_startRenderIdx.removeOnChange(_startRenderIdxCallbackHandle);
_sizeRender.removeOnChange(_sizeRenderCallbackHandle);
_startRenderIdx.setMaxValue(static_cast<unsigned int>(_numObjects - 1));
_sizeRender.setMaxValue(static_cast<unsigned int>(_numObjects));
_startRenderIdx = static_cast<unsigned int>(0);
_sizeRender = static_cast<unsigned int>(_numObjects);
_startRenderIdxCallbackHandle = _startRenderIdx.onChange(_updateStartRenderIdxSelect);
_sizeRenderCallbackHandle = _sizeRender.onChange(_updateRenderSizeSelect);
// If a limit wasn't specified in dictionary, set it to # lines in file
// minus the header line (but temporarily disable callback to avoid 2nd call)
_upperLimit.removeOnChange(_upperLimitCallbackHandle);
if (_sizeRender == 0u) {
_sizeRender = static_cast<unsigned int>(_numObjects);
}
_upperLimit.setMaxValue(static_cast<unsigned int>(_numObjects));
_upperLimit = static_cast<unsigned int>(_numObjects);
_upperLimitCallbackHandle = _upperLimit.onChange(_reinitializeTrailBuffers);
if (_upperLimit == 0u) {
_upperLimit = static_cast<unsigned int>(_numObjects);
}
}
void RenderableSmallBody::skipSingleLineInFile(std::ifstream& file) {
@@ -312,7 +338,7 @@ void RenderableSmallBody::readOrbitalParamsFromThisLine(bool firstDataLine,
// Object designator string
std::getline(file, name, ',');
if (_startRenderIdx > 0 && _startRenderIdx == (csvLine - 1)) {
if (_startRenderIdx > 0 && _startRenderIdx == (csvLine - 1) && _sizeRender == 1) {
formatObjectName(name);
LINFO(fmt::format("Set render block to start at object {}", name));
}

View File

@@ -38,6 +38,8 @@
namespace openspace {
namespace documentation { struct Documentation; }
class RenderableSmallBody : public RenderableOrbitalKepler {
public:
RenderableSmallBody(const ghoul::Dictionary& dictionary);
@@ -51,10 +53,17 @@ private:
void skipSingleLineInFile(std::ifstream& file);
std::vector<std::string> _sbNames;
std::function<void()> _updateContiguousModeSelect;
std::function<void()> _updateRenderUpperLimitSelect;
/// The index array that is potentially used in the draw call. If this is empty, no
/// element draw call is used.
std::vector<unsigned int> _indexBufferData;
bool contiguousMode = true;
properties::BoolProperty _contiguousMode;
properties::UIntProperty _upperLimit;
properties::Property::OnChangeHandle _contiguousModeCallbackhandle;
properties::Property::OnChangeHandle _upperLimitCallbackHandle;
};
} // namespace openspace

View File

@@ -308,10 +308,10 @@ namespace {
struct [[codegen::Dictionary(RenderableStars)]] Parameters {
// The path to the SPECK file containing information about the stars being rendered
std::string speckFile [[codegen::key("File")]];
std::filesystem::path speckFile [[codegen::key("File")]];
// [[codegen::verbatim(ColorTextureInfo.description)]]
std::string colorMap;
std::filesystem::path colorMap;
enum class ColorOption {
Color,
@@ -350,7 +350,7 @@ namespace {
std::string renderMethod;
// [[codegen::verbatim(PsfTextureInfo.description)]]
std::string texture;
std::filesystem::path texture;
// [[codegen::verbatim(SizeCompositionOptionInfo.description)]]
std::optional<std::string> sizeComposition;
@@ -434,11 +434,11 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary)
addProperty(_opacity);
registerUpdateRenderBinFromOpacity();
_speckFile = absPath(p.speckFile);
_speckFile = p.speckFile.string();
_speckFile.onChange([&]() { _speckFileIsDirty = true; });
addProperty(_speckFile);
_colorTexturePath = absPath(p.colorMap);
_colorTexturePath = p.colorMap.string();
_colorTextureFile = std::make_unique<File>(_colorTexturePath);
/*_shapeTexturePath = absPath(dictionary.value<std::string>(
@@ -525,7 +525,7 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary)
_renderingMethodOption = RenderOptionTexture;
}
_pointSpreadFunctionTexturePath = absPath(p.texture);
_pointSpreadFunctionTexturePath = absPath(p.texture.string());
_pointSpreadFunctionFile = std::make_unique<File>(_pointSpreadFunctionTexturePath);
_pointSpreadFunctionTexturePath.onChange([&]() {
_pointSpreadFunctionTextureIsDirty = true;
@@ -1237,13 +1237,13 @@ void RenderableStars::loadShapeTexture() {
*/
void RenderableStars::loadData() {
std::string _file = _speckFile;
if (!FileSys.fileExists(absPath(_file))) {
std::string file = absPath(_speckFile);
if (!FileSys.fileExists(file)) {
return;
}
std::string cachedFile = FileSys.cacheManager()->cachedFilename(
_file,
file,
ghoul::filesystem::CacheManager::Persistent::Yes
);
@@ -1255,7 +1255,7 @@ void RenderableStars::loadData() {
bool hasCachedFile = FileSys.fileExists(cachedFile);
if (hasCachedFile) {
LINFO(fmt::format("Cached file '{}' used for Speck file '{}'",
cachedFile, _file
cachedFile, file
));
bool success = loadCachedFile(cachedFile);
@@ -1263,15 +1263,15 @@ void RenderableStars::loadData() {
return;
}
else {
FileSys.cacheManager()->removeCacheFile(_file);
FileSys.cacheManager()->removeCacheFile(file);
// Intentional fall-through to the 'else' computation to generate the cache
// file for the next run
}
}
else {
LINFO(fmt::format("Cache for Speck file '{}' not found", _file));
LINFO(fmt::format("Cache for Speck file '{}' not found", file));
}
LINFO(fmt::format("Loading Speck file '{}'", _file));
LINFO(fmt::format("Loading Speck file '{}'", file));
readSpeckFile();

View File

@@ -254,7 +254,7 @@ glm::dvec3 KeplerTranslation::position(const UpdateData& data) const {
_orbitPlaneDirty = false;
}
const double t = data.time.j2000Seconds() -_epoch;
const double t = data.time.j2000Seconds() - _epoch;
const double meanMotion = glm::two_pi<double>() / _period;
const double meanAnomaly = glm::radians(_meanAnomalyAtEpoch.value()) + t * meanMotion;
const double e = eccentricAnomaly(meanAnomaly);

View File

@@ -481,7 +481,7 @@ void RenderablePlanetProjection::imageProjectGPU(
if (_geometry->hasProperty("Radius")) {
std::any r = _geometry->property("Radius")->get();
if (glm::vec3* radius = std::any_cast<glm::vec3>(&r)){
_fboProgramObject->setUniform(_fboUniformCache.radius, radius);
_fboProgramObject->setUniform(_fboUniformCache.radius, *radius);
}
}
else {

View File

@@ -135,8 +135,8 @@ void BasicVolumeRaycaster::preRaycast(const RaycastData& data,
int nClips = static_cast<int>(clipNormals.size());
program.setUniform("nClips_" + id, nClips);
program.setUniform("clipNormals_" + id, clipNormals.data(), nClips);
program.setUniform("clipOffsets_" + id, clipOffsets.data(), nClips);
program.setUniform("clipNormals_" + id, clipNormals);
program.setUniform("clipOffsets_" + id, clipOffsets);
program.setUniform("opacity_" + id, _opacity);
program.setUniform("rNormalization_" + id, _rNormalization);
program.setUniform("rUpperBound_" + id, _rUpperBound);

View File

@@ -101,11 +101,15 @@ void GenerateRawVolumeTask::perform(const Task::ProgressCallback& progressCallba
ghoul::lua::LuaState state;
ghoul::lua::runScript(state, _valueFunctionLua);
#if (defined(NDEBUG) || defined(DEBUG))
ghoul::lua::verifyStackSize(state, 1);
#endif
int functionReference = luaL_ref(state, LUA_REGISTRYINDEX);
#if (defined(NDEBUG) || defined(DEBUG))
ghoul::lua::verifyStackSize(state, 0);
#endif
glm::vec3 domainSize = _upperDomainBound - _lowerDomainBound;
@@ -117,14 +121,18 @@ void GenerateRawVolumeTask::perform(const Task::ProgressCallback& progressCallba
glm::vec3 coord = _lowerDomainBound +
glm::vec3(cell) / glm::vec3(_dimensions) * domainSize;
#if (defined(NDEBUG) || defined(DEBUG))
ghoul::lua::verifyStackSize(state, 0);
#endif
lua_rawgeti(state, LUA_REGISTRYINDEX, functionReference);
lua_pushnumber(state, coord.x);
lua_pushnumber(state, coord.y);
lua_pushnumber(state, coord.z);
#if (defined(NDEBUG) || defined(DEBUG))
ghoul::lua::verifyStackSize(state, 4);
#endif
if (lua_pcall(state, 3, 1, 0) != LUA_OK) {
return;

View File

@@ -167,6 +167,11 @@ ModuleConfigurations = {
},
Space = {
ShowExceptions = false
},
Exoplanets = {
ShowComparisonCircle = false,
ShowHabitableZone = true,
UseOptimisticZone = true
}
}

View File

@@ -0,0 +1,43 @@
-- This script gets two parameters in its global scope:
-- filename: The full path for the file that was dropped on the application.
-- Example: C:/OpenSpace/openspace.cfg
-- basename: Only the name of the actual file with extension, but without the full rest
-- of the path.
-- Example: openspace.cfg
-- extension: The extention of the file
-- Example: .cfg
--
-- From this script, we need to return the script that we want to be executed in response
-- to the drag event. If we don't want anything to happen, don't return anything or
-- return an empty string
if filename == nil or filename == "" or
basename == nil or basename == "" or
extension == nil or extension == "" then
do return "" end
end
-- Lua doesn't enjoy \ that are used by Windows extensively. So we convert all \ into /
filename = filename:gsub("\\", "/")
basename = basename:gsub("\\", "/")
basename_without_extension = basename:sub(0, #basename - extension:len())
is_image_file = function(extension)
return extension == ".png" or extension == ".jpg" or extension == ".jpeg" or
extension == ".tif" or extension == ".tga" or extension == ".bmp" or
extension == ".psd" or extension == ".gif" or extension == ".hdr" or
extension == ".pic" or extension == ".pnm"
end
if is_image_file(extension) then
identifier = basename_without_extension:gsub(" ", "_")
return [[openspace.addScreenSpaceRenderable({
Identifier = "]] .. identifier .. [[",
Type = "ScreenSpaceImageLocal",
TexturePath = "]] .. filename .. [["
});]]
elseif extension == ".asset" then
return [[openspace.asset.add("]] .. filename .. [[")]]
elseif extension == ".osrec" or extension == ".osrectxt" then
return [[openspace.sessionRecording.startPlayback("]] .. basename .. [[")]]
end

View File

@@ -71,14 +71,18 @@ std::string to_string(const openspace::documentation::TestResult& value) {
}
else {
std::stringstream stream;
stream << "Failure." << '\n';
stream << "Specification Failure. ";
for (const TestResult::Offense& offense : value.offenses) {
stream << " " << ghoul::to_string(offense) << '\n';
stream << fmt::format(" {}", ghoul::to_string(offense));
if (!offense.explanation.empty()) {
stream << fmt::format(" ({})", offense.explanation);
}
stream << '\n';
}
for (const TestResult::Warning& warning : value.warnings) {
stream << " " << ghoul::to_string(warning) << '\n';
stream << fmt::format(" {}\n", ghoul::to_string(warning));
}
return stream.str();
@@ -129,17 +133,26 @@ namespace openspace::documentation {
const std::string DocumentationEntry::Wildcard = "*";
//std::string concatenate(const std::vector<TestResult::Offense>& offenses) {
// std::string result = "Error in specification (";
// for (const TestResult::Offense& o : offenses) {
// if (o.explanation.empty()) {
// result += fmt::format("{} ({}), ", o.offender, ghoul::to_string(o.reason));
// }
// else {
// result += fmt::format("{} ({}: {}), ", o.offender, ghoul::to_string(o.reason), o.explanation);
// }
// }
// result.pop_back();
// result.back() = ')';
// return result;
//}
SpecificationError::SpecificationError(TestResult res, std::string comp)
: ghoul::RuntimeError("Error in specification", std::move(comp))
, result(std::move(res))
{
ghoul_assert(!result.success, "Result's success must be false");
message += " (";
for (const TestResult::Offense& o : result.offenses) {
message += o.offender + ',';
}
message.back() = ')';
}
DocumentationEntry::DocumentationEntry(std::string k, std::shared_ptr<Verifier> v,

View File

@@ -27,6 +27,7 @@
#include <openspace/documentation/documentationengine.h>
#include <ghoul/misc/misc.h>
#include <algorithm>
#include <filesystem>
namespace openspace::documentation {
@@ -177,6 +178,121 @@ std::string StringVerifier::type() const {
return "String";
}
TestResult FileVerifier::operator()(const ghoul::Dictionary& dict,
const std::string& key) const
{
TestResult res = StringVerifier::operator()(dict, key);
if (!res.success) {
return res;
}
std::string file = dict.value<std::string>(key);
if (!std::filesystem::exists(file) || !std::filesystem::is_regular_file(file)) {
res.success = false;
TestResult::Offense off;
off.offender = key;
off.reason = TestResult::Offense::Reason::Verification;
off.explanation = "File did not exist";
res.offenses.push_back(off);
}
return res;
}
std::string FileVerifier::type() const {
return "File";
}
TestResult DirectoryVerifier::operator()(const ghoul::Dictionary& dict,
const std::string& key) const
{
TestResult res = StringVerifier::operator()(dict, key);
if (!res.success) {
return res;
}
std::string dir = dict.value<std::string>(key);
if (!std::filesystem::exists(dir) || !std::filesystem::is_directory(dir)) {
res.success = false;
TestResult::Offense off;
off.offender = key;
off.reason = TestResult::Offense::Reason::Verification;
off.explanation = "Directory did not exist";
res.offenses.push_back(off);
}
return res;
}
std::string DirectoryVerifier::type() const {
return "Directory";
}
TestResult Color3Verifier::operator()(const ghoul::Dictionary& dictionary,
const std::string& key) const
{
TestResult res = Vector3Verifier<double>::operator()(dictionary, key);
if (!res.success) {
return res;
}
glm::dvec3 values = dictionary.value<glm::dvec3>(key);
if (values.x < 0.0 || values.x > 1.0) {
res.success = false;
res.offenses.push_back({ key + ".x", TestResult::Offense::Reason::Verification });
}
if (values.y < 0.0 || values.y > 1.0) {
res.success = false;
res.offenses.push_back({ key + ".y", TestResult::Offense::Reason::Verification });
}
if (values.z < 0.0 || values.z > 1.0) {
res.success = false;
res.offenses.push_back({ key + ".z", TestResult::Offense::Reason::Verification });
}
return res;
}
std::string Color3Verifier::type() const {
return std::string("Color3");
}
TestResult Color4Verifier::operator()(const ghoul::Dictionary& dictionary,
const std::string& key) const
{
TestResult res = Vector4Verifier<double>::operator()(dictionary, key);
if (!res.success) {
return res;
}
std::vector<double> values = dictionary.value<std::vector<double>>(key);
if (values[0] < 0.0 || values[0] > 1.0) {
res.success = false;
res.offenses.push_back({ key + ".x", TestResult::Offense::Reason::Verification });
}
if (values[1] < 0.0 || values[1] > 1.0) {
res.success = false;
res.offenses.push_back({ key + ".y", TestResult::Offense::Reason::Verification });
}
if (values[2] < 0.0 || values[2] > 1.0) {
res.success = false;
res.offenses.push_back({ key + ".z", TestResult::Offense::Reason::Verification });
}
if (values[3] < 0.0 || values[3] > 1.0) {
res.success = false;
res.offenses.push_back({ key + ".a", TestResult::Offense::Reason::Verification });
}
return res;
}
std::string Color4Verifier::type() const {
return std::string("Color4");
}
template <>
TestResult TemplateVerifier<glm::ivec2>::operator()(const ghoul::Dictionary& dict,
const std::string& key) const

View File

@@ -24,6 +24,7 @@
#include <openspace/engine/moduleengine.h>
#include <openspace/documentation/documentation.h>
#include <openspace/moduleregistration.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/util/openspacemodule.h>
@@ -58,7 +59,20 @@ void ModuleEngine::initialize(
if (it != moduleConfigurations.end()) {
configuration = it->second;
}
m->initialize(configuration);
try {
m->initialize(configuration);
}
catch (const documentation::SpecificationError& e) {
//LFATALC(e.component, e.message);
for (const documentation::TestResult::Offense& o : e.result.offenses) {
LERRORC(e.component, o.offender + ": " + ghoul::to_string(o.reason));
}
for (const documentation::TestResult::Warning& w : e.result.warnings) {
LWARNINGC(e.component, w.offender + ": " + ghoul::to_string(w.reason));
}
throw;
}
addPropertySubOwner(m);
}

View File

@@ -71,7 +71,6 @@
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/font/fontmanager.h>
#include <ghoul/font/fontrenderer.h>
#include <ghoul/logging/consolelog.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/logging/visualstudiooutputlog.h>
#include <ghoul/misc/profiling.h>
@@ -83,6 +82,7 @@
#include <ghoul/systemcapabilities/openglcapabilitiescomponent.h>
#include <glbinding/glbinding.h>
#include <glbinding-aux/types_to_string.h>
#include <filesystem>
#include <future>
#include <numeric>
#include <sstream>
@@ -234,7 +234,6 @@ void OpenSpaceEngine::initialize() {
using ImmediateFlush = ghoul::logging::LogManager::ImmediateFlush;
ghoul::logging::LogManager::initialize(level, ImmediateFlush(immediateFlush));
LogMgr.addLog(std::make_unique<ghoul::logging::ConsoleLog>());
for (const ghoul::Dictionary& log : global::configuration->logging.logs) {
try {
@@ -1444,6 +1443,52 @@ void OpenSpaceEngine::touchExitCallback(TouchInput input) {
}
}
void OpenSpaceEngine::handleDragDrop(const std::string& file) {
std::filesystem::path f(file);
ghoul::lua::LuaState s(ghoul::lua::LuaState::IncludeStandardLibrary::Yes);
std::string absolutePath = absPath("${SCRIPTS}/drag_drop_handler.lua");
int status = luaL_loadfile(s, absolutePath.c_str());
if (status != LUA_OK) {
std::string error = lua_tostring(s, -1);
LERROR(error);
return;
}
ghoul::lua::push(s, file);
lua_setglobal(s, "filename");
std::string basename = f.filename().string();
ghoul::lua::push(s, basename);
lua_setglobal(s, "basename");
std::string extension = f.extension().string();
std::transform(
extension.begin(), extension.end(),
extension.begin(),
[](char c) { return static_cast<char>(::tolower(c)); }
);
ghoul::lua::push(s, extension);
lua_setglobal(s, "extension");
status = lua_pcall(s, 0, 1, 0);
if (status != LUA_OK) {
std::string error = lua_tostring(s, -1);
LERROR(error);
return;
}
if (lua_isnil(s, -1)) {
LWARNING(fmt::format("Unhandled file dropped: {}", file));
return;
}
std::string script = ghoul::lua::value<std::string>(s);
global::scriptEngine->queueScript(
script,
scripting::ScriptEngine::RemoteScripting::Yes
);
}
std::vector<std::byte> OpenSpaceEngine::encode() {
ZoneScoped

View File

@@ -45,6 +45,9 @@ SceneGraphNode* sceneGraphNode(const std::string& name) {
const Renderable* renderable(const std::string& name) {
SceneGraphNode* node = sceneGraphNode(name);
if (!node) {
return nullptr;
}
return node->renderable();
}

View File

@@ -520,9 +520,8 @@ bool Asset::initialize() {
loader()->callOnInitialize(this);
}
catch (const ghoul::lua::LuaRuntimeException& e) {
LERROR(fmt::format(
"Failed to initialize asset {}; {}: {}", id(), e.component, e.message
));
LERROR(fmt::format("Failed to initialize asset {}", id()));
LERROR(fmt::format("{}: {}", e.component, e.message));
// TODO: rollback;
setState(State::InitializationFailed);
return false;

View File

@@ -27,7 +27,6 @@
#include <openspace/engine/openspaceengine.h>
#include <ghoul/misc/defer.h>
#include <ghoul/misc/easing.h>
#include <regex>
namespace openspace {
@@ -68,59 +67,144 @@ void applyRegularExpression(lua_State* L, const std::string& regex,
using ghoul::lua::luaTypeToString;
const bool isGroupMode = !groupName.empty();
bool isLiteral = false;
const int type = lua_type(L, -1);
// Extract the property and node name to be searched for from regex
std::string propertyName = "";
std::string nodeName = "";
size_t wildPos = regex.find_first_of("*");
if (wildPos != std::string::npos) {
nodeName = regex.substr(0, wildPos);
propertyName = regex.substr(wildPos + 1, regex.length());
// If none then malformed regular expression
if (propertyName.empty() && nodeName.empty()) {
LERRORC(
"applyRegularExpression",
fmt::format(
"Malformed regular expression: '{}': "
"Empty both before and after '*'", regex
)
);
return;
}
// Currently do not support several wildcards
if (regex.find_first_of("*", wildPos + 1) != std::string::npos) {
LERRORC(
"applyRegularExpression",
fmt::format(
"Malformed regular expression: '{}': "
"Currently only one '*' is supported", regex
)
);
return;
}
}
// Literal or tag
else {
propertyName = regex;
if (!isGroupMode) {
isLiteral = true;
}
}
// Stores whether we found at least one matching property. If this is false at the end
// of the loop, the property name regex was probably misspelled.
bool foundMatching = false;
std::regex r(regex);
for (properties::Property* prop : properties) {
// Check the regular expression for all properties
const std::string& id = prop->fullyQualifiedIdentifier();
if (std::regex_match(id, r)) {
// If the fully qualified id matches the regular expression, we queue the
// value change if the types agree
if (isGroupMode) {
properties::PropertyOwner* matchingTaggedOwner =
findPropertyOwnerWithMatchingGroupTag(
prop,
groupName
);
if (!matchingTaggedOwner) {
if (isLiteral && id != propertyName) {
continue;
}
else if (!propertyName.empty()){
size_t propertyPos = id.find(propertyName);
if (propertyPos != std::string::npos) {
// Check that the propertyName fully matches the property in id
if ((propertyPos + propertyName.length() + 1) < id.length()) {
continue;
}
// Match node name
if (!nodeName.empty() && id.find(nodeName) == std::string::npos) {
continue;
}
// Check tag
if (isGroupMode) {
properties::PropertyOwner* matchingTaggedOwner =
findPropertyOwnerWithMatchingGroupTag(
prop,
groupName
);
if (!matchingTaggedOwner) {
continue;
}
}
}
else {
continue;
}
}
else if (!nodeName.empty()) {
size_t nodePos = id.find(nodeName);
if (nodePos != std::string::npos) {
// Check tag
if (isGroupMode) {
properties::PropertyOwner* matchingTaggedOwner =
findPropertyOwnerWithMatchingGroupTag(
prop,
groupName
);
if (!matchingTaggedOwner) {
continue;
}
}
// Check that the nodeName fully matches the node in id
else if (nodePos != 0) {
continue;
}
}
else {
continue;
}
}
if (type != prop->typeLua()) {
LERRORC(
"property_setValue",
fmt::format(
"{}: Property '{}' does not accept input of type '{}'. "
"Requested type: '{}'",
errorLocation(L),
prop->fullyQualifiedIdentifier(),
luaTypeToString(type),
luaTypeToString(prop->typeLua())
)
);
// Check that the types match
if (type != prop->typeLua()) {
LERRORC(
"property_setValue",
fmt::format(
"{}: Property '{}' does not accept input of type '{}'. "
"Requested type: '{}'",
errorLocation(L),
prop->fullyQualifiedIdentifier(),
luaTypeToString(type),
luaTypeToString(prop->typeLua())
)
);
}
else {
// If the fully qualified id matches the regular expression, we queue the
// value change if the types agree
foundMatching = true;
if (interpolationDuration == 0.0) {
global::renderEngine->scene()->removePropertyInterpolation(prop);
prop->setLuaValue(L);
}
else {
foundMatching = true;
if (interpolationDuration == 0.0) {
global::renderEngine->scene()->removePropertyInterpolation(prop);
prop->setLuaValue(L);
}
else {
prop->setLuaInterpolationTarget(L);
global::renderEngine->scene()->addPropertyInterpolation(
prop,
static_cast<float>(interpolationDuration),
easingFunction
);
}
prop->setLuaInterpolationTarget(L);
global::renderEngine->scene()->addPropertyInterpolation(
prop,
static_cast<float>(interpolationDuration),
easingFunction
);
}
}
}
@@ -150,15 +234,8 @@ bool doesUriContainGroupTag(const std::string& command, std::string& groupName)
}
}
std::string replaceUriWithGroupName(const std::string& uri, const std::string& ownerName)
{
size_t pos = uri.find_first_of(".");
return ownerName + "." + uri.substr(pos);
}
std::string extractUriWithoutGroupName(const std::string& uri) {
size_t pos = uri.find_first_of(".");
return uri.substr(pos);
std::string removeGroupNameFromUri(const std::string& uri) {
return uri.substr(uri.find_first_of("."));
}
} // namespace
@@ -275,60 +352,31 @@ int property_setValue(lua_State* L) {
}
if (optimization.empty()) {
// Replace all wildcards * with the correct regex (.*)
size_t startPos = uriOrRegex.find("*");
while (startPos != std::string::npos) {
uriOrRegex.replace(startPos, 1, "(.*)");
startPos += 4; // (.*)
startPos = uriOrRegex.find("*", startPos);
}
std::string groupName;
if (doesUriContainGroupTag(uriOrRegex, groupName)) {
std::string pathRemainderToMatch = extractUriWithoutGroupName(uriOrRegex);
// Remove group name from start of regex and replace with '.*'
uriOrRegex = replaceUriWithGroupName(uriOrRegex, ".*");
// Remove group name from start of regex and replace with '*'
uriOrRegex = removeGroupNameFromUri(uriOrRegex);
}
try {
applyRegularExpression(
L,
uriOrRegex,
allProperties(),
interpolationDuration,
groupName,
easingMethod
);
}
catch (const std::regex_error& e) {
LERRORC(
"property_setValue",
fmt::format(
"Malformed regular expression: '{}': {}", uriOrRegex, e.what()
)
);
}
applyRegularExpression(
L,
uriOrRegex,
allProperties(),
interpolationDuration,
groupName,
easingMethod
);
return 0;
}
else if (optimization == "regex") {
try {
applyRegularExpression(
L,
uriOrRegex,
allProperties(),
interpolationDuration,
"",
easingMethod
);
}
catch (const std::regex_error& e) {
LERRORC(
"property_setValueRegex",
fmt::format(
"Malformed regular expression: '{}': {}", uriOrRegex, e.what()
)
);
}
applyRegularExpression(
L,
uriOrRegex,
allProperties(),
interpolationDuration,
"",
easingMethod
);
}
else if (optimization == "single") {
properties::Property* prop = property(uriOrRegex);
@@ -445,44 +493,116 @@ int property_getProperty(lua_State* L) {
std::string groupName;
if (doesUriContainGroupTag(regex, groupName)) {
std::string pathRemainderToMatch = extractUriWithoutGroupName(regex);
// Remove group name from start of regex and replace with '.*'
regex = replaceUriWithGroupName(regex, ".*");
// Remove group name from start of regex and replace with '*'
regex = removeGroupNameFromUri(regex);
}
// Replace all wildcards * with the correct regex (.*)
size_t startPos = regex.find("*");
while (startPos != std::string::npos) {
regex.replace(startPos, 1, "(.*)");
startPos += 4; // (.*)
startPos = regex.find("*", startPos);
// Extract the property and node name to be searched for from regex
bool isLiteral = false;
std::string propertyName = "";
std::string nodeName = "";
size_t wildPos = regex.find_first_of("*");
if (wildPos != std::string::npos) {
nodeName = regex.substr(0, wildPos);
propertyName = regex.substr(wildPos + 1, regex.length());
// If none then malformed regular expression
if (propertyName.empty() && nodeName.empty()) {
LERRORC(
"property_getProperty",
fmt::format(
"Malformed regular expression: '{}': "
"Empty both before and after '*'", regex
)
);
return 0;
}
// Currently do not support several wildcards
if (regex.find_first_of("*", wildPos + 1) != std::string::npos) {
LERRORC(
"property_getProperty",
fmt::format(
"Malformed regular expression: '{}': "
"Currently only one '*' is supported", regex
)
);
return 0;
}
}
// Literal or tag
else {
propertyName = regex;
if (groupName.empty()) {
isLiteral = true;
}
}
// Get all matching property uris and save to res
std::regex r(regex);
std::vector<properties::Property*> props = allProperties();
std::vector<std::string> res;
for (properties::Property* prop : props) {
// Check the regular expression for all properties
const std::string& id = prop->fullyQualifiedIdentifier();
if (std::regex_match(id, r)) {
// Filter on the groupname if there was one
if (!groupName.empty()) {
properties::PropertyOwner* matchingTaggedOwner =
findPropertyOwnerWithMatchingGroupTag(
prop,
groupName
);
if (!matchingTaggedOwner) {
if (isLiteral && id != propertyName) {
continue;
}
else if (!propertyName.empty()) {
size_t propertyPos = id.find(propertyName);
if (propertyPos != std::string::npos) {
// Check that the propertyName fully matches the property in id
if ((propertyPos + propertyName.length() + 1) < id.length()) {
continue;
}
res.push_back(id);
// Match node name
if (!nodeName.empty() && id.find(nodeName) == std::string::npos) {
continue;
}
// Check tag
if (!groupName.empty()) {
properties::PropertyOwner* matchingTaggedOwner =
findPropertyOwnerWithMatchingGroupTag(
prop,
groupName
);
if (!matchingTaggedOwner) {
continue;
}
}
}
else {
res.push_back(id);
continue;
}
}
else if (!nodeName.empty()) {
size_t nodePos = id.find(nodeName);
if (nodePos != std::string::npos) {
// Check tag
if (!groupName.empty()) {
properties::PropertyOwner* matchingTaggedOwner =
findPropertyOwnerWithMatchingGroupTag(
prop,
groupName
);
if (!matchingTaggedOwner) {
continue;
}
}
// Check that the nodeName fully matches the node in id
else if (nodePos != 0) {
continue;
}
}
else {
continue;
}
}
res.push_back(id);
}
lua_newtable(L);
@@ -528,10 +648,10 @@ int addSceneGraphNode(lua_State* L) {
global::renderEngine->scene()->initializeNode(node);
}
catch (const documentation::SpecificationError& e) {
LERRORC("Scene", ghoul::to_string(e.result));
return ghoul::lua::luaError(
L,
fmt::format("Error loading scene graph node: {}: {}",
e.what(), ghoul::to_string(e.result))
fmt::format("Error loading scene graph node: {}", e.what())
);
}
catch (const ghoul::RuntimeError& e) {
@@ -602,33 +722,94 @@ int removeSceneGraphNodesFromRegex(lua_State* L) {
const std::vector<SceneGraphNode*>& nodes =
global::renderEngine->scene()->allSceneGraphNodes();
// Replace all wildcards * with the correct regex (.*)
size_t startPos = name.find("*");
while (startPos != std::string::npos) {
name.replace(startPos, 1, "(.*)");
startPos += 4; // (.*)
startPos = name.find("*", startPos);
// Extract the property and node name to be searched for from name
bool isLiteral = false;
std::string propertyName = "";
std::string nodeName = "";
size_t wildPos = name.find_first_of("*");
if (wildPos != std::string::npos) {
nodeName = name.substr(0, wildPos);
propertyName = name.substr(wildPos + 1, name.length());
// If none then malformed regular expression
if (propertyName.empty() && nodeName.empty()) {
LERRORC(
"removeSceneGraphNodesFromRegex",
fmt::format(
"Malformed regular expression: '{}': "
"Empty both before and after '*'", name
)
);
return 0;
}
// Currently do not support several wildcards
if (name.find_first_of("*", wildPos + 1) != std::string::npos) {
LERRORC(
"removeSceneGraphNodesFromRegex",
fmt::format(
"Malformed regular expression: '{}': "
"Currently only one '*' is supported", name
)
);
return 0;
}
}
// Literal or tag
else {
propertyName = name;
isLiteral = true;
}
bool foundMatch = false;
std::vector<SceneGraphNode*> markedList;
std::regex r(name);
for (SceneGraphNode* node : nodes) {
const std::string& identifier = node->identifier();
if (std::regex_match(identifier, r)) {
foundMatch = true;
SceneGraphNode* parent = node->parent();
if (!parent) {
LERRORC(
"removeSceneGraphNodesFromRegex",
fmt::format("Cannot remove root node")
);
if (isLiteral && identifier != propertyName) {
continue;
}
else if (!propertyName.empty()) {
size_t propertyPos = identifier.find(propertyName);
if (propertyPos != std::string::npos) {
// Check that the propertyName fully matches the property in id
if ((propertyPos + propertyName.length() + 1) < identifier.length()) {
continue;
}
// Match node name
if (!nodeName.empty() && identifier.find(nodeName) == std::string::npos) {
continue;
}
}
else {
markedList.push_back(node);
continue;
}
}
else if (!nodeName.empty()) {
size_t nodePos = identifier.find(nodeName);
if (nodePos != std::string::npos) {
// Check that the nodeName fully matches the node in id
if (nodePos != 0) {
continue;
}
}
else {
continue;
}
}
foundMatch = true;
SceneGraphNode* parent = node->parent();
if (!parent) {
LERRORC(
"removeSceneGraphNodesFromRegex",
fmt::format("Cannot remove root node")
);
}
else {
markedList.push_back(node);
}
}
if (!foundMatch) {