mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-05 03:00:58 -06:00
Merge branch 'master' into feature/model-animation
* Resolve conflicts
This commit is contained in:
2
Jenkinsfile
vendored
2
Jenkinsfile
vendored
@@ -107,7 +107,7 @@ linux_gcc_make: {
|
||||
}
|
||||
stage('linux-gcc-make/build') {
|
||||
def cmakeCompileOptions = moduleCMakeFlags();
|
||||
cmakeCompileOptions += ' -DMAKE_BUILD_TYPE=Release';
|
||||
cmakeCompileOptions += ' -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS:STRING="-DGLM_ENABLE_EXPERIMENTAL" -DOpenGL_GL_PREFERENCE:STRING=GLVND';
|
||||
// Not sure why the linking of OpenSpaceTest takes so long
|
||||
compileHelper.build(compileHelper.Make(), compileHelper.Gcc(), cmakeCompileOptions, 'OpenSpace', 'build-make');
|
||||
compileHelper.recordCompileIssues(compileHelper.Gcc());
|
||||
|
||||
@@ -348,8 +348,8 @@ local Rex = {
|
||||
Target = "EARTH",
|
||||
Instrument = "NH_REX",
|
||||
Color = {
|
||||
Start = { 1.0, 0.7, 0.0, 1.0},
|
||||
End = {0.0, 0.0, 0.0, 0.0 }
|
||||
Start = { 1.0, 0.7, 0.0, 1.0 },
|
||||
End = { 0.0, 0.0, 0.0, 0.0 }
|
||||
}
|
||||
},
|
||||
Transform = {
|
||||
|
||||
Submodule ext/ghoul updated: a49caf0d5a...fc69a527bc
@@ -45,17 +45,27 @@ template <typename T>
|
||||
TestResult TemplateVerifier<T>::operator()(const ghoul::Dictionary& dict,
|
||||
const std::string& key) const
|
||||
{
|
||||
TestResult res;
|
||||
if (dict.hasValue<Type>(key)) {
|
||||
return { true, {}, {} };
|
||||
res.success = true;
|
||||
}
|
||||
else {
|
||||
res.success = false;
|
||||
|
||||
if (dict.hasKey(key)) {
|
||||
return { false, { { key, TestResult::Offense::Reason::WrongType } }, {} };
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
res.offenses.push_back(o);
|
||||
}
|
||||
else {
|
||||
return { false, { { key, TestResult::Offense::Reason::MissingKey } }, {} };
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::MissingKey;
|
||||
res.offenses.push_back(o);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -143,7 +153,13 @@ TestResult OperatorVerifier<T, Operator>::operator()(const ghoul::Dictionary& di
|
||||
val = static_cast<int>(d);
|
||||
}
|
||||
else {
|
||||
return { false, { { key, TestResult::Offense::Reason::WrongType } }, {} };
|
||||
TestResult r;
|
||||
r.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -153,7 +169,13 @@ TestResult OperatorVerifier<T, Operator>::operator()(const ghoul::Dictionary& di
|
||||
return { true, {}, {} };
|
||||
}
|
||||
else {
|
||||
return { false, { { key, TestResult::Offense::Reason::Verification } }, {} };
|
||||
TestResult r;
|
||||
r.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -210,7 +232,13 @@ TestResult InListVerifier<T>::operator()(const ghoul::Dictionary& dict,
|
||||
return { true, {}, {} };
|
||||
}
|
||||
else {
|
||||
return { false, { { key, TestResult::Offense::Reason::Verification } }, {} };
|
||||
TestResult r;
|
||||
r.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -256,7 +284,13 @@ TestResult NotInListVerifier<T>::operator()(const ghoul::Dictionary& dict,
|
||||
return { true, {}, {} };
|
||||
}
|
||||
else {
|
||||
return { false, { { key, TestResult::Offense::Reason::Verification } }, {} };
|
||||
TestResult r;
|
||||
r.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -306,7 +340,13 @@ TestResult InRangeVerifier<T>::operator()(const ghoul::Dictionary& dict,
|
||||
val = static_cast<int>(d);
|
||||
}
|
||||
else {
|
||||
return { false, { { key, TestResult::Offense::Reason::WrongType } }, {} };
|
||||
TestResult r;
|
||||
r.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -317,7 +357,13 @@ TestResult InRangeVerifier<T>::operator()(const ghoul::Dictionary& dict,
|
||||
return { true, {}, {} };
|
||||
}
|
||||
else {
|
||||
return { false, { { key, TestResult::Offense::Reason::Verification } }, {} };
|
||||
TestResult r;
|
||||
r.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -353,7 +399,13 @@ TestResult NotInRangeVerifier<T>::operator()(const ghoul::Dictionary& dict,
|
||||
val = static_cast<int>(d);
|
||||
}
|
||||
else {
|
||||
return { false, { { key, TestResult::Offense::Reason::WrongType } }, {} };
|
||||
TestResult r;
|
||||
r.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -361,7 +413,13 @@ TestResult NotInRangeVerifier<T>::operator()(const ghoul::Dictionary& dict,
|
||||
}
|
||||
|
||||
if (val >= lower && val <= upper) {
|
||||
return { false, { { key, TestResult::Offense::Reason::Verification } }, {} };
|
||||
TestResult r;
|
||||
r.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
r.offenses.push_back(o);
|
||||
return r;
|
||||
}
|
||||
else {
|
||||
return { true, {}, {} };
|
||||
@@ -396,9 +454,10 @@ TestResult DeprecatedVerifier<T>::operator()(const ghoul::Dictionary& dict,
|
||||
const std::string& key) const
|
||||
{
|
||||
TestResult res = T::operator()(dict, key);
|
||||
res.warnings.push_back(
|
||||
TestResult::Warning{ key, TestResult::Warning::Reason::Deprecated }
|
||||
);
|
||||
TestResult::Warning w;
|
||||
w.offender = key;
|
||||
w.reason = TestResult::Warning::Reason::Deprecated;
|
||||
res.warnings.push_back(w);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,4 +53,4 @@ protected:
|
||||
|
||||
} // openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___DASHBOARDITEM___H__
|
||||
#endif // __OPENSPACE_CORE___DASHBOARDTEXTITEM___H__
|
||||
|
||||
@@ -47,6 +47,8 @@ struct LuaLibrary;
|
||||
class ScriptScheduler {
|
||||
public:
|
||||
struct ScheduledScript {
|
||||
ScheduledScript() = default;
|
||||
ScheduledScript(const ghoul::Dictionary& dict);
|
||||
|
||||
double time = -std::numeric_limits<double>::max();
|
||||
std::string forwardScript;
|
||||
|
||||
@@ -179,7 +179,8 @@ namespace {
|
||||
// A list of objects that cast light on this atmosphere
|
||||
std::vector<CasterElement> casters;
|
||||
};
|
||||
// Declares shadow groups, meaning which nodes are considered in shadow calculations
|
||||
// Declares shadow groups, meaning which nodes are considered in shadow
|
||||
// calculations
|
||||
std::optional<ShadowGroup> shadowGroup;
|
||||
|
||||
// [[codegen::verbatim(AtmosphereHeightInfo.description)]]
|
||||
@@ -360,7 +361,7 @@ RenderableAtmosphere::RenderableAtmosphere(const ghoul::Dictionary& dictionary)
|
||||
|
||||
_mieScatteringExtinctionPropCoefficient.onChange(updateWithCalculation);
|
||||
addProperty(_mieScatteringExtinctionPropCoefficient);
|
||||
|
||||
|
||||
if (p.debug.has_value()) {
|
||||
_preCalculatedTexturesScale =
|
||||
p.debug->preCalculatedTextureScale.value_or(_preCalculatedTexturesScale);
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace {
|
||||
struct [[codegen::Dictionary(DashboardItemDate)]] Parameters {
|
||||
// [[codegen::verbatim(FormatStringInfo.description)]]
|
||||
std::optional<std::string> formatString;
|
||||
|
||||
|
||||
// [[codegen::verbatim(TimeFormatInfo.description)]]
|
||||
std::optional<std::string> timeFormat;
|
||||
};
|
||||
|
||||
@@ -132,7 +132,8 @@ namespace {
|
||||
DtAvg [[codegen::key("Average Deltatime")]],
|
||||
DtExtremes [[codegen::key("Deltatime extremes")]],
|
||||
DtStandardDeviation [[codegen::key("Deltatime standard deviation")]],
|
||||
DtCoefficientOfVariation [[codegen::key("Deltatime coefficient of variation")]],
|
||||
DtCoefficientOfVariation
|
||||
[[codegen::key("Deltatime coefficient of variation")]],
|
||||
FPS [[codegen::key("Frames per second")]],
|
||||
FPSAvg [[codegen::key("Average frames per second")]]
|
||||
};
|
||||
@@ -187,7 +188,8 @@ DashboardItemFramerate::DashboardItemFramerate(const ghoul::Dictionary& dictiona
|
||||
_frametimeType = static_cast<int>(FrametimeType::DtStandardDeviation);
|
||||
break;
|
||||
case Parameters::Type::DtCoefficientOfVariation:
|
||||
_frametimeType = static_cast<int>(FrametimeType::DtCoefficientOfVariation);
|
||||
_frametimeType =
|
||||
static_cast<int>(FrametimeType::DtCoefficientOfVariation);
|
||||
break;
|
||||
case Parameters::Type::FPS:
|
||||
_frametimeType = static_cast<int>(FrametimeType::FPS);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
|
||||
// This class is using a VBO ring buffer + a constantly updated point as follows:
|
||||
// Structure of the array with a _resolution of 16. FF denotes the floating position that
|
||||
@@ -104,36 +105,32 @@ namespace {
|
||||
"Opaque, Transparent, or Overlay rendering step. Default is Transparent."
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(RenderableTrailOrbit)]] Parameters {
|
||||
// [[codegen::verbatim(PeriodInfo.description)]]
|
||||
double period;
|
||||
|
||||
// [[codegen::verbatim(ResolutionInfo.description)]]
|
||||
int resolution;
|
||||
|
||||
enum class RenderableType {
|
||||
Background,
|
||||
Opaque,
|
||||
PreDeferredTransparent,
|
||||
PostDeferredTransparent,
|
||||
Overlay
|
||||
};
|
||||
|
||||
// [[codegen::verbatim(RenderableTypeInfo.description)]]
|
||||
std::optional<RenderableType> renderableType;
|
||||
};
|
||||
#include "renderabletrailorbit_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation RenderableTrailOrbit::Documentation() {
|
||||
using namespace documentation;
|
||||
documentation::Documentation doc {
|
||||
"RenderableTrailOrbit",
|
||||
"base_renderable_renderabletrailorbit",
|
||||
{
|
||||
{
|
||||
PeriodInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::No,
|
||||
PeriodInfo.description
|
||||
},
|
||||
{
|
||||
ResolutionInfo.identifier,
|
||||
new IntVerifier,
|
||||
Optional::No,
|
||||
ResolutionInfo.description
|
||||
},
|
||||
{
|
||||
RenderableTypeInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
RenderableTypeInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "base_renderable_renderabletrailorbit";
|
||||
|
||||
// Insert the parents documentation entries until we have a verifier that can deal
|
||||
// with class hierarchy
|
||||
@@ -152,46 +149,42 @@ RenderableTrailOrbit::RenderableTrailOrbit(const ghoul::Dictionary& dictionary)
|
||||
, _period(PeriodInfo, 0.0, 0.0, 1e9)
|
||||
, _resolution(ResolutionInfo, 10000, 1, 1000000)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"RenderableTrailOrbit"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_translation->onParameterChange([this]() { _needsFullSweep = true; });
|
||||
|
||||
// Period is in days
|
||||
using namespace std::chrono;
|
||||
const long long sph = duration_cast<seconds>(hours(24)).count();
|
||||
_period = dictionary.value<double>(PeriodInfo.identifier) * sph;
|
||||
_period = p.period * duration_cast<seconds>(hours(24)).count();
|
||||
_period.onChange([&] { _needsFullSweep = true; _indexBufferDirty = true; });
|
||||
addProperty(_period);
|
||||
|
||||
_resolution = static_cast<int>(dictionary.value<double>(ResolutionInfo.identifier));
|
||||
_resolution = p.resolution;
|
||||
_resolution.onChange([&] { _needsFullSweep = true; _indexBufferDirty = true; });
|
||||
addProperty(_resolution);
|
||||
|
||||
// We store the vertices with (excluding the wrapping) decending temporal order
|
||||
_primaryRenderInformation.sorting = RenderInformation::VertexSorting::NewestFirst;
|
||||
|
||||
if (dictionary.hasKey(RenderableTypeInfo.identifier)) {
|
||||
std::string renderType = dictionary.value<std::string>(
|
||||
RenderableTypeInfo.identifier
|
||||
);
|
||||
if (renderType == "Background") {
|
||||
setRenderBin(Renderable::RenderBin::Background);
|
||||
}
|
||||
else if (renderType == "Opaque") {
|
||||
setRenderBin(Renderable::RenderBin::Opaque);
|
||||
}
|
||||
else if (renderType == "PreDeferredTransparent") {
|
||||
setRenderBin(Renderable::RenderBin::PreDeferredTransparent);
|
||||
}
|
||||
else if (renderType == "PostDeferredTransparent") {
|
||||
setRenderBin(Renderable::RenderBin::PostDeferredTransparent);
|
||||
}
|
||||
else if (renderType == "Overlay") {
|
||||
setRenderBin(Renderable::RenderBin::Overlay);
|
||||
if (p.renderableType.has_value()) {
|
||||
switch (*p.renderableType) {
|
||||
case Parameters::RenderableType::Background:
|
||||
setRenderBin(Renderable::RenderBin::Background);
|
||||
break;
|
||||
case Parameters::RenderableType::Opaque:
|
||||
setRenderBin(Renderable::RenderBin::Opaque);
|
||||
break;
|
||||
case Parameters::RenderableType::PreDeferredTransparent:
|
||||
setRenderBin(Renderable::RenderBin::PreDeferredTransparent);
|
||||
break;
|
||||
case Parameters::RenderableType::PostDeferredTransparent:
|
||||
setRenderBin(Renderable::RenderBin::PostDeferredTransparent);
|
||||
break;
|
||||
case Parameters::RenderableType::Overlay:
|
||||
setRenderBin(Renderable::RenderBin::Overlay);
|
||||
break;
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <openspace/scene/translation.h>
|
||||
#include <openspace/util/spicemanager.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <optional>
|
||||
|
||||
// This class creates the entire trajectory at once and keeps it in memory the entire
|
||||
// time. This means that there is no need for updating the trail at runtime, but also that
|
||||
@@ -81,49 +82,31 @@ namespace {
|
||||
"If this value is set to 'true', the entire trail will be rendered; if it is "
|
||||
"'false', only the trail until the current time in the application will be shown."
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(RenderableTrailTrajectory)]] Parameters {
|
||||
// [[codegen::verbatim(StartTimeInfo.description)]]
|
||||
std::string startTime [[codegen::annotation("A valid date in ISO 8601 format")]];
|
||||
|
||||
// [[codegen::verbatim(EndTimeInfo.description)]]
|
||||
std::string endTime [[codegen::annotation("A valid date in ISO 8601 format")]];
|
||||
|
||||
// [[codegen::verbatim(SampleIntervalInfo.description)]]
|
||||
double sampleInterval;
|
||||
|
||||
// [[codegen::verbatim(TimeSubSampleInfo.description)]]
|
||||
std::optional<int> timeStampSubsampleFactor;
|
||||
|
||||
// [[codegen::verbatim(RenderFullPathInfo.description)]]
|
||||
std::optional<bool> showFullTrail;
|
||||
};
|
||||
#include "renderabletrailtrajectory_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation RenderableTrailTrajectory::Documentation() {
|
||||
using namespace documentation;
|
||||
|
||||
documentation::Documentation doc {
|
||||
"RenderableTrailTrajectory",
|
||||
"base_renderable_renderabletrailtrajectory",
|
||||
{
|
||||
{
|
||||
StartTimeInfo.identifier,
|
||||
new StringAnnotationVerifier("A valid date in ISO 8601 format"),
|
||||
Optional::No,
|
||||
StartTimeInfo.description
|
||||
},
|
||||
{
|
||||
EndTimeInfo.identifier,
|
||||
new StringAnnotationVerifier("A valid date in ISO 8601 format"),
|
||||
Optional::No,
|
||||
EndTimeInfo.description
|
||||
},
|
||||
{
|
||||
SampleIntervalInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::No,
|
||||
SampleIntervalInfo.description
|
||||
},
|
||||
{
|
||||
TimeSubSampleInfo.identifier,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
TimeSubSampleInfo.description
|
||||
},
|
||||
{
|
||||
RenderFullPathInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
RenderFullPathInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "base_renderable_renderabletrailtrajectory";
|
||||
|
||||
// @TODO cleanup
|
||||
// Insert the parents documentation entries until we have a verifier that can deal
|
||||
@@ -146,37 +129,28 @@ RenderableTrailTrajectory::RenderableTrailTrajectory(const ghoul::Dictionary& di
|
||||
, _timeStampSubsamplingFactor(TimeSubSampleInfo, 1, 1, 1000000000)
|
||||
, _renderFullTrail(RenderFullPathInfo, false)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"RenderableTrailTrajectory"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_translation->onParameterChange([this]() { _needsFullSweep = true; });
|
||||
|
||||
_startTime = dictionary.value<std::string>(StartTimeInfo.identifier);
|
||||
_startTime = p.startTime;
|
||||
_startTime.onChange([this] { _needsFullSweep = true; });
|
||||
addProperty(_startTime);
|
||||
|
||||
_endTime = dictionary.value<std::string>(EndTimeInfo.identifier);
|
||||
_endTime = p.endTime;
|
||||
_endTime.onChange([this] { _needsFullSweep = true; });
|
||||
addProperty(_endTime);
|
||||
|
||||
_sampleInterval = dictionary.value<double>(SampleIntervalInfo.identifier);
|
||||
_sampleInterval = p.sampleInterval;
|
||||
_sampleInterval.onChange([this] { _needsFullSweep = true; });
|
||||
addProperty(_sampleInterval);
|
||||
|
||||
if (dictionary.hasValue<double>(TimeSubSampleInfo.identifier)) {
|
||||
_timeStampSubsamplingFactor = static_cast<int>(
|
||||
dictionary.value<double>(TimeSubSampleInfo.identifier)
|
||||
);
|
||||
}
|
||||
_timeStampSubsamplingFactor =
|
||||
p.timeStampSubsampleFactor.value_or(_timeStampSubsamplingFactor);
|
||||
_timeStampSubsamplingFactor.onChange([this] { _subsamplingIsDirty = true; });
|
||||
addProperty(_timeStampSubsamplingFactor);
|
||||
|
||||
if (dictionary.hasValue<bool>(RenderFullPathInfo.identifier)) {
|
||||
_renderFullTrail = dictionary.value<bool>(RenderFullPathInfo.identifier);
|
||||
}
|
||||
_renderFullTrail = p.showFullTrail.value_or(_renderFullTrail);
|
||||
addProperty(_renderFullTrail);
|
||||
|
||||
// We store the vertices with ascending temporal order
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace {
|
||||
struct [[codegen::Dictionary(FixedRotation)]] Parameters {
|
||||
// This value specifies the direction of the new X axis. If this value is not
|
||||
// specified, it will be computed by completing a right handed coordinate system
|
||||
// from the Y and Z axis, which must be specified instead. If this value is a
|
||||
// from the Y and Z axis, which must be specified instead. If this value is a
|
||||
// string, it is interpreted as the identifier of another scenegraph node. If this
|
||||
// value is a 3-vector, it is interpreted as a direction vector
|
||||
std::optional<std::variant<std::string, glm::vec3>> xAxis;
|
||||
|
||||
@@ -30,48 +30,32 @@
|
||||
#include <openspace/util/time.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyKeyframes = "Keyframes";
|
||||
struct [[codegen::Dictionary(TimelineRotation)]] Parameters {
|
||||
// A table of keyframes, with keys formatted as YYYY-MM-DDTHH:MM:SS and values
|
||||
// that are valid Rotation objects
|
||||
std::map<std::string, ghoul::Dictionary> keyframes
|
||||
[[codegen::reference("core_transform_rotation")]];
|
||||
};
|
||||
#include "timelinerotation_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation TimelineRotation::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"Timeline Rotation",
|
||||
"base_transform_rotation_keyframe",
|
||||
{
|
||||
{
|
||||
KeyKeyframes,
|
||||
new TableVerifier({
|
||||
{ "*", new TableVerifier(), Optional::No, "Any translation object" }
|
||||
}),
|
||||
Optional::No,
|
||||
"A table of keyframes, with keys formatted as YYYY-MM-DDTHH:MM:SS"
|
||||
"and values that are valid Rotation objects."
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "base_transform_rotation_keyframe";
|
||||
return doc;
|
||||
}
|
||||
|
||||
TimelineRotation::TimelineRotation(const ghoul::Dictionary& dictionary) {
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"TimelineTranslation"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
const ghoul::Dictionary& keyframes =
|
||||
dictionary.value<ghoul::Dictionary>(KeyKeyframes);
|
||||
|
||||
for (std::string_view timeString : keyframes.keys()) {
|
||||
const double t = Time::convertTime(std::string(timeString));
|
||||
|
||||
ghoul::mm_unique_ptr<Rotation> rotation =
|
||||
Rotation::createFromDictionary(
|
||||
keyframes.value<ghoul::Dictionary>(timeString)
|
||||
);
|
||||
for (const std::pair<const std::string, ghoul::Dictionary>& kf : p.keyframes) {
|
||||
const double t = Time::convertTime(kf.first);
|
||||
|
||||
ghoul::mm_unique_ptr<Rotation> rotation = Rotation::createFromDictionary(
|
||||
kf.second
|
||||
);
|
||||
if (rotation) {
|
||||
_timeline.addKeyframe(t, std::move(rotation));
|
||||
}
|
||||
|
||||
@@ -30,48 +30,31 @@
|
||||
#include <openspace/util/time.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyKeyframes = "Keyframes";
|
||||
struct [[codegen::Dictionary(TimelineTranslation)]] Parameters {
|
||||
// A table of keyframes, with keys formatted as YYYY-MM-DDTHH:MM:SS and values
|
||||
// that are valid Translation objects
|
||||
std::map<std::string, ghoul::Dictionary> keyframes
|
||||
[[codegen::reference("core_transform_translation")]];
|
||||
};
|
||||
#include "timelinetranslation_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation TimelineTranslation::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"Timeline Translation",
|
||||
"base_transform_translation_keyframe",
|
||||
{
|
||||
{
|
||||
KeyKeyframes,
|
||||
new TableVerifier({
|
||||
{ "*", new TableVerifier(), Optional::No, "Any translation object" }
|
||||
}),
|
||||
Optional::No,
|
||||
"A table of keyframes, with keys formatted as YYYY-MM-DDTHH:MM:SS"
|
||||
"and values that are valid Translation objects."
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "base_transform_translation_keyframe";
|
||||
return doc;
|
||||
}
|
||||
|
||||
TimelineTranslation::TimelineTranslation(const ghoul::Dictionary& dictionary) {
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"TimelineTranslation"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
const ghoul::Dictionary& keyframes =
|
||||
dictionary.value<ghoul::Dictionary>(KeyKeyframes);
|
||||
|
||||
for (std::string_view timeString : keyframes.keys()) {
|
||||
const double t = Time::convertTime(std::string(timeString));
|
||||
for (const std::pair<const std::string, ghoul::Dictionary>& kf : p.keyframes) {
|
||||
const double t = Time::convertTime(kf.first);
|
||||
|
||||
ghoul::mm_unique_ptr<Translation> translation =
|
||||
Translation::createFromDictionary(
|
||||
keyframes.value<ghoul::Dictionary>(timeString)
|
||||
);
|
||||
|
||||
Translation::createFromDictionary(kf.second);
|
||||
if (translation) {
|
||||
_timeline.addKeyframe(t, std::move(translation));
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/opengl/textureunit.h>
|
||||
#include <optional>
|
||||
|
||||
namespace {
|
||||
enum Origin {
|
||||
@@ -72,47 +73,38 @@ namespace {
|
||||
"Texture Coordinate Origin",
|
||||
"The origin of the texture coorinate system."
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(RenderableDebugPlane)]] Parameters {
|
||||
// [[codegen::verbatim(TextureInfo.description)]]
|
||||
std::optional<int> texture;
|
||||
|
||||
// [[codegen::verbatim(BillboardInfo.description)]]
|
||||
std::optional<bool> billboard;
|
||||
|
||||
// [[codegen::verbatim(SizeInfo.description)]]
|
||||
std::optional<float> size;
|
||||
|
||||
enum class Origin {
|
||||
LowerLeft,
|
||||
LowerRight,
|
||||
UpperLeft,
|
||||
UpperRight,
|
||||
Center
|
||||
};
|
||||
// [[codegen::verbatim(OriginInfo.description)]]
|
||||
std::optional<Origin> origin;
|
||||
};
|
||||
#include "renderabledebugplane_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation RenderableDebugPlane::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"RenderableDebugPlane",
|
||||
"debugging_renderable_debugplane",
|
||||
{
|
||||
{
|
||||
TextureInfo.identifier,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
TextureInfo.description
|
||||
},
|
||||
{
|
||||
BillboardInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
BillboardInfo.description
|
||||
},
|
||||
{
|
||||
SizeInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
SizeInfo.description
|
||||
},
|
||||
{
|
||||
OriginInfo.identifier,
|
||||
new StringInListVerifier(
|
||||
{ "LowerLeft", "LowerRight", "UpperLeft", "UpperRight", "Center" }
|
||||
),
|
||||
Optional::Yes,
|
||||
OriginInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "debugging_renderable_debugplane";
|
||||
return doc;
|
||||
}
|
||||
|
||||
|
||||
RenderableDebugPlane::RenderableDebugPlane(const ghoul::Dictionary& dictionary)
|
||||
: Renderable(dictionary)
|
||||
, _texture(TextureInfo, -1, -1, 512)
|
||||
@@ -120,17 +112,18 @@ RenderableDebugPlane::RenderableDebugPlane(const ghoul::Dictionary& dictionary)
|
||||
, _size(SizeInfo, 10.f, 0.f, 1e25f)
|
||||
, _origin(OriginInfo, properties::OptionProperty::DisplayType::Dropdown)
|
||||
{
|
||||
if (dictionary.hasKey(TextureInfo.identifier)) {
|
||||
_texture = static_cast<int>(dictionary.value<double>(TextureInfo.identifier));
|
||||
}
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
if (dictionary.hasKey(SizeInfo.identifier)) {
|
||||
_size = static_cast<float>(dictionary.value<double>(SizeInfo.identifier));
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(BillboardInfo.identifier)) {
|
||||
_billboard = dictionary.value<bool>(BillboardInfo.identifier);
|
||||
}
|
||||
_texture = p.texture.value_or(_texture);
|
||||
addProperty(_texture);
|
||||
|
||||
_size.onChange([this](){ _planeIsDirty = true; });
|
||||
_size = p.size.value_or(_size);
|
||||
setBoundingSphere(_size);
|
||||
addProperty(_size);
|
||||
|
||||
_billboard = p.billboard.value_or(_billboard);
|
||||
addProperty(_billboard);
|
||||
|
||||
_origin.addOptions({
|
||||
{ LowerLeft, "LowerLeft" },
|
||||
@@ -141,36 +134,30 @@ RenderableDebugPlane::RenderableDebugPlane(const ghoul::Dictionary& dictionary)
|
||||
});
|
||||
_origin.setValue(Center);
|
||||
|
||||
if (dictionary.hasKey(OriginInfo.identifier)) {
|
||||
const std::string origin = dictionary.value<std::string>(OriginInfo.identifier);
|
||||
if (origin == "LowerLeft") {
|
||||
_origin = LowerLeft;
|
||||
}
|
||||
else if (origin == "LowerRight") {
|
||||
_origin = LowerRight;
|
||||
}
|
||||
else if (origin == "UpperLeft") {
|
||||
_origin = UpperLeft;
|
||||
}
|
||||
else if (origin == "UpperRight") {
|
||||
_origin = UpperRight;
|
||||
}
|
||||
else if (origin == "Center") {
|
||||
_origin = Center;
|
||||
if (p.origin.has_value()) {
|
||||
switch (*p.origin) {
|
||||
case Parameters::Origin::LowerLeft:
|
||||
_origin = LowerLeft;
|
||||
break;
|
||||
case Parameters::Origin::LowerRight:
|
||||
_origin = LowerRight;
|
||||
break;
|
||||
case Parameters::Origin::UpperLeft:
|
||||
_origin = UpperLeft;
|
||||
break;
|
||||
case Parameters::Origin::UpperRight:
|
||||
_origin = UpperRight;
|
||||
break;
|
||||
case Parameters::Origin::Center:
|
||||
_origin = Center;
|
||||
break;
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}
|
||||
else {
|
||||
_origin = Center;
|
||||
}
|
||||
|
||||
addProperty(_texture);
|
||||
|
||||
addProperty(_billboard);
|
||||
|
||||
addProperty(_size);
|
||||
_size.onChange([this](){ _planeIsDirty = true; });
|
||||
|
||||
setBoundingSphere(_size);
|
||||
}
|
||||
|
||||
bool RenderableDebugPlane::isReady() const {
|
||||
|
||||
@@ -68,7 +68,7 @@ private:
|
||||
properties::FloatProperty _size;
|
||||
properties::OptionProperty _origin;
|
||||
|
||||
bool _planeIsDirty;
|
||||
bool _planeIsDirty = true;
|
||||
|
||||
std::unique_ptr<ghoul::opengl::ProgramObject> _shader;
|
||||
|
||||
|
||||
@@ -56,7 +56,8 @@ namespace openspace::exoplanets::luascriptfunctions {
|
||||
|
||||
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);
|
||||
constexpr const float JupiterRadius =
|
||||
static_cast<float>(distanceconstants::JupiterRadius);
|
||||
|
||||
ExoplanetSystem findExoplanetSystemInData(std::string_view starName) {
|
||||
const ExoplanetsModule* module = global::moduleEngine->module<ExoplanetsModule>();
|
||||
|
||||
@@ -126,7 +126,7 @@ RenderableFieldlines::RenderableFieldlines(const ghoul::Dictionary& dictionary)
|
||||
else {
|
||||
_vectorFieldInfo = dictionary.value<ghoul::Dictionary>(KeyVectorField);
|
||||
}
|
||||
|
||||
|
||||
if (!dictionary.hasValue<ghoul::Dictionary>(KeyFieldlines)) {
|
||||
LERROR(fmt::format("Renderable does not contain a key for '{}'", KeyFieldlines));
|
||||
}
|
||||
|
||||
@@ -300,199 +300,123 @@ namespace {
|
||||
"Report GL Errors",
|
||||
"If set to true, any OpenGL errors will be reported if encountered"
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(RenderableGaiaStars)]] Parameters {
|
||||
// [[codegen::verbatim(FilePathInfo.description)]]
|
||||
std::string file;
|
||||
|
||||
enum class FileReader {
|
||||
Fits,
|
||||
Speck,
|
||||
BinaryRaw,
|
||||
BinaryOctree,
|
||||
StreamOctree
|
||||
};
|
||||
// [[codegen::verbatim(FileReaderOptionInfo.description)]]
|
||||
FileReader fileReaderOption;
|
||||
|
||||
enum class RenderOption {
|
||||
Static,
|
||||
Color,
|
||||
Motion
|
||||
};
|
||||
// [[codegen::verbatim(RenderOptionInfo.description)]]
|
||||
std::optional<RenderOption> renderOption;
|
||||
|
||||
enum class ShaderOption {
|
||||
PointSSBO [[codegen::key("Point_SSBO")]],
|
||||
PointVBO [[codegen::key("Point_VBO")]],
|
||||
BillboardSSBO [[codegen::key("Billboard_SSBO")]],
|
||||
BillboardVBO [[codegen::key("Billboard_VBO")]],
|
||||
BillboardSSBONoFBO [[codegen::key("Billboard_SSBO_noFBO")]]
|
||||
};
|
||||
// [codegen::verbatim(ShaderOptionInfo.description)]]
|
||||
std::optional<ShaderOption> shaderOption;
|
||||
|
||||
// [codegen::verbatim(PsfTextureInfo.description)]]
|
||||
std::string texture;
|
||||
|
||||
// [codegen::verbatim(ColorTextureInfo.description)]]
|
||||
std::string colorMap;
|
||||
|
||||
// [codegen::verbatim(LuminosityMultiplierInfo.description)]]
|
||||
std::optional<float> luminosityMultiplier;
|
||||
|
||||
// [codegen::verbatim(MagnitudeBoostInfo.description)]]
|
||||
std::optional<float> magnitudeBoost;
|
||||
|
||||
// [codegen::verbatim(CutOffThresholdInfo.description)]]
|
||||
std::optional<float> cutOffThreshold;
|
||||
|
||||
// [codegen::verbatim(SharpnessInfo.description)]]
|
||||
std::optional<float> sharpness;
|
||||
|
||||
// [codegen::verbatim(BillboardSizeInfo.description)]]
|
||||
std::optional<float> billboardSize;
|
||||
|
||||
// [codegen::verbatim(CloseUpBoostDistInfo.description)]]
|
||||
std::optional<float> closeUpBoostDist;
|
||||
|
||||
// [codegen::verbatim(TmPointFilterSizeInfo.description)]]
|
||||
std::optional<int> filterSize;
|
||||
|
||||
// [codegen::verbatim(TmPointSigmaInfo.description)]]
|
||||
std::optional<float> sigma;
|
||||
|
||||
// [codegen::verbatim(AdditionalNodesInfo.description)]]
|
||||
std::optional<glm::ivec2> additionalNodes;
|
||||
|
||||
// [codegen::verbatim(TmPointPxThresholdInfo.description)]]
|
||||
std::optional<float> pixelWeightThreshold;
|
||||
|
||||
// [codegen::verbatim(FirstRowInfo.description)]]
|
||||
std::optional<int> firstRow;
|
||||
|
||||
// [codegen::verbatim(LastRowInfo.description)]]
|
||||
std::optional<int> lastRow;
|
||||
|
||||
// [codegen::verbatim(ColumnNamesInfo.description)]]
|
||||
std::optional<std::vector<std::string>> columnNames;
|
||||
|
||||
// [codegen::verbatim(LodPixelThresholdInfo.description)]]
|
||||
std::optional<float> lodPixelThreshold;
|
||||
|
||||
// [codegen::verbatim(MaxGpuMemoryPercentInfo.description)]]
|
||||
std::optional<float> maxGpuMemoryPercent;
|
||||
|
||||
// [codegen::verbatim(MaxCpuMemoryPercentInfo.description)]]
|
||||
std::optional<float> maxCpuMemoryPercent;
|
||||
|
||||
// [codegen::verbatim(FilterPosXInfo.description)]]
|
||||
std::optional<glm::vec2> filterPosX;
|
||||
|
||||
// [codegen::verbatim(FilterPosYInfo.description)]]
|
||||
std::optional<glm::vec2> filterPosY;
|
||||
|
||||
// [codegen::verbatim(FilterPosZInfo.description)]]
|
||||
std::optional<glm::vec2> filterPosZ;
|
||||
|
||||
// [codegen::verbatim(FilterGMagInfo.description)]]
|
||||
std::optional<glm::vec2> filterGMag;
|
||||
|
||||
// [codegen::verbatim(FilterBpRpInfo.description)]]
|
||||
std::optional<glm::vec2> filterBpRp;
|
||||
|
||||
// [codegen::verbatim(FilterDistInfo.description)]]
|
||||
std::optional<glm::vec2> filterDist;
|
||||
|
||||
// [codegen::verbatim(ReportGlErrorsInfo.description)]]
|
||||
std::optional<bool> reportGlErrors;
|
||||
};
|
||||
#include "renderablegaiastars_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation RenderableGaiaStars::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"RenderableGaiaStars",
|
||||
"gaiamission_renderablegaiastars",
|
||||
{
|
||||
{
|
||||
FilePathInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
FilePathInfo.description
|
||||
},
|
||||
{
|
||||
FileReaderOptionInfo.identifier,
|
||||
new StringInListVerifier({
|
||||
"Fits", "Speck", "BinaryRaw", "BinaryOctree", "StreamOctree"
|
||||
}),
|
||||
Optional::No,
|
||||
FileReaderOptionInfo.description
|
||||
},
|
||||
{
|
||||
RenderOptionInfo.identifier,
|
||||
new StringInListVerifier({
|
||||
"Static", "Color", "Motion"
|
||||
}),
|
||||
Optional::Yes,
|
||||
RenderOptionInfo.description
|
||||
},
|
||||
{
|
||||
ShaderOptionInfo.identifier,
|
||||
new StringInListVerifier({
|
||||
"Point_SSBO", "Point_VBO", "Billboard_SSBO", "Billboard_VBO",
|
||||
"Billboard_SSBO_noFBO"
|
||||
}),
|
||||
Optional::Yes,
|
||||
ShaderOptionInfo.description
|
||||
},
|
||||
{
|
||||
PsfTextureInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
PsfTextureInfo.description
|
||||
},
|
||||
{
|
||||
ColorTextureInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
ColorTextureInfo.description
|
||||
},
|
||||
{
|
||||
LuminosityMultiplierInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LuminosityMultiplierInfo.description
|
||||
},
|
||||
{
|
||||
MagnitudeBoostInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
MagnitudeBoostInfo.description
|
||||
},
|
||||
{
|
||||
CutOffThresholdInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
CutOffThresholdInfo.description
|
||||
},
|
||||
{
|
||||
SharpnessInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
SharpnessInfo.description
|
||||
},
|
||||
{
|
||||
BillboardSizeInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
BillboardSizeInfo.description
|
||||
},
|
||||
{
|
||||
CloseUpBoostDistInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
CloseUpBoostDistInfo.description
|
||||
},
|
||||
{
|
||||
TmPointFilterSizeInfo.identifier,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
TmPointFilterSizeInfo.description
|
||||
},
|
||||
{
|
||||
TmPointSigmaInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
TmPointSigmaInfo.description
|
||||
},
|
||||
{
|
||||
AdditionalNodesInfo.identifier,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
AdditionalNodesInfo.description
|
||||
},
|
||||
{
|
||||
TmPointPxThresholdInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
TmPointPxThresholdInfo.description
|
||||
},
|
||||
{
|
||||
FirstRowInfo.identifier,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
FirstRowInfo.description
|
||||
},
|
||||
{
|
||||
LastRowInfo.identifier,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
LastRowInfo.description
|
||||
},
|
||||
{
|
||||
ColumnNamesInfo.identifier,
|
||||
new StringListVerifier,
|
||||
Optional::Yes,
|
||||
ColumnNamesInfo.description
|
||||
},
|
||||
{
|
||||
LodPixelThresholdInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LodPixelThresholdInfo.description
|
||||
},
|
||||
{
|
||||
MaxGpuMemoryPercentInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
MaxGpuMemoryPercentInfo.description
|
||||
},
|
||||
{
|
||||
MaxCpuMemoryPercentInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
MaxCpuMemoryPercentInfo.description
|
||||
},
|
||||
{
|
||||
FilterPosXInfo.identifier,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
FilterPosXInfo.description
|
||||
},
|
||||
{
|
||||
FilterPosYInfo.identifier,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
FilterPosYInfo.description
|
||||
},
|
||||
{
|
||||
FilterPosZInfo.identifier,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
FilterPosZInfo.description
|
||||
},
|
||||
{
|
||||
FilterGMagInfo.identifier,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
FilterGMagInfo.description
|
||||
},
|
||||
{
|
||||
FilterBpRpInfo.identifier,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
FilterBpRpInfo.description
|
||||
},
|
||||
{
|
||||
FilterDistInfo.identifier,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
FilterDistInfo.description
|
||||
},
|
||||
{
|
||||
ReportGlErrorsInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
ReportGlErrorsInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "gaiamission_renderablegaiastars";
|
||||
return doc;
|
||||
}
|
||||
|
||||
RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary)
|
||||
@@ -536,13 +460,9 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary)
|
||||
{
|
||||
using File = ghoul::filesystem::File;
|
||||
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"RenderableGaiaStars"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_filePath = absPath(dictionary.value<std::string>(FilePathInfo.identifier));
|
||||
_filePath = absPath(p.file);
|
||||
_dataFile = std::make_unique<File>(_filePath);
|
||||
_dataFile->setCallback([&](const File&) { _dataIsDirty = true; });
|
||||
|
||||
@@ -556,25 +476,24 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary)
|
||||
{ gaia::FileReaderOption::BinaryOctree, "BinaryOctree" },
|
||||
{ gaia::FileReaderOption::StreamOctree, "StreamOctree" }
|
||||
});
|
||||
if (dictionary.hasKey(FileReaderOptionInfo.identifier)) {
|
||||
const std::string fileReaderOption = dictionary.value<std::string>(
|
||||
FileReaderOptionInfo.identifier
|
||||
);
|
||||
if (fileReaderOption == "Fits") {
|
||||
switch (p.fileReaderOption) {
|
||||
case Parameters::FileReader::Fits:
|
||||
_fileReaderOption = gaia::FileReaderOption::Fits;
|
||||
}
|
||||
else if (fileReaderOption == "Speck") {
|
||||
break;
|
||||
case Parameters::FileReader::Speck:
|
||||
_fileReaderOption = gaia::FileReaderOption::Speck;
|
||||
}
|
||||
else if (fileReaderOption == "BinaryRaw") {
|
||||
break;
|
||||
case Parameters::FileReader::BinaryRaw:
|
||||
_fileReaderOption = gaia::FileReaderOption::BinaryRaw;
|
||||
}
|
||||
else if (fileReaderOption == "BinaryOctree") {
|
||||
break;
|
||||
case Parameters::FileReader::BinaryOctree:
|
||||
_fileReaderOption = gaia::FileReaderOption::BinaryOctree;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
case Parameters::FileReader::StreamOctree:
|
||||
_fileReaderOption = gaia::FileReaderOption::StreamOctree;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
|
||||
_renderOption.addOptions({
|
||||
@@ -582,18 +501,19 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary)
|
||||
{ gaia::RenderOption::Color, "Color" },
|
||||
{ gaia::RenderOption::Motion, "Motion" }
|
||||
});
|
||||
if (dictionary.hasKey(RenderOptionInfo.identifier)) {
|
||||
const std::string renderOption = dictionary.value<std::string>(
|
||||
RenderOptionInfo.identifier
|
||||
);
|
||||
if (renderOption == "Static") {
|
||||
_renderOption = gaia::RenderOption::Static;
|
||||
}
|
||||
else if (renderOption == "Color") {
|
||||
_renderOption = gaia::RenderOption::Color;
|
||||
}
|
||||
else {
|
||||
_renderOption = gaia::RenderOption::Motion;
|
||||
if (p.renderOption.has_value()) {
|
||||
switch (*p.renderOption) {
|
||||
case Parameters::RenderOption::Static:
|
||||
_renderOption = gaia::RenderOption::Static;
|
||||
break;
|
||||
case Parameters::RenderOption::Color:
|
||||
_renderOption = gaia::RenderOption::Color;
|
||||
break;
|
||||
case Parameters::RenderOption::Motion:
|
||||
_renderOption = gaia::RenderOption::Motion;
|
||||
break;
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}
|
||||
_renderOption.onChange([&]() { _buffersAreDirty = true; });
|
||||
@@ -614,31 +534,31 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary)
|
||||
});
|
||||
#endif // __APPLE__
|
||||
|
||||
if (dictionary.hasKey(ShaderOptionInfo.identifier)) {
|
||||
// Default shader option:
|
||||
_shaderOption = gaia::ShaderOption::Billboard_VBO;
|
||||
|
||||
const std::string shaderOption = dictionary.value<std::string>(
|
||||
ShaderOptionInfo.identifier
|
||||
);
|
||||
|
||||
#ifndef __APPLE__
|
||||
if (shaderOption == "Point_SSBO") {
|
||||
_shaderOption = gaia::ShaderOption::Point_SSBO;
|
||||
}
|
||||
else if (shaderOption == "Billboard_SSBO") {
|
||||
_shaderOption = gaia::ShaderOption::Billboard_SSBO;
|
||||
}
|
||||
else if (shaderOption == "Billboard_SSBO_noFBO") {
|
||||
_shaderOption = gaia::ShaderOption::Billboard_SSBO_noFBO;
|
||||
}
|
||||
if (p.shaderOption.has_value()) {
|
||||
switch (*p.shaderOption) {
|
||||
case Parameters::ShaderOption::PointSSBO:
|
||||
_shaderOption = gaia::ShaderOption::Point_SSBO;
|
||||
break;
|
||||
case Parameters::ShaderOption::PointVBO:
|
||||
#ifdef __APPLE__
|
||||
throw ghoul::RuntimeError("Shader option is not supported on MacOS");
|
||||
#endif // __APPLE__
|
||||
|
||||
if (shaderOption == "Point_VBO") {
|
||||
_shaderOption = gaia::ShaderOption::Point_VBO;
|
||||
}
|
||||
else if (shaderOption == "Billboard_VBO") {
|
||||
_shaderOption = gaia::ShaderOption::Billboard_VBO;
|
||||
_shaderOption = gaia::ShaderOption::Point_VBO;
|
||||
break;
|
||||
case Parameters::ShaderOption::BillboardSSBO:
|
||||
_shaderOption = gaia::ShaderOption::Billboard_SSBO;
|
||||
break;
|
||||
case Parameters::ShaderOption::BillboardVBO:
|
||||
#ifdef __APPLE__
|
||||
throw ghoul::RuntimeError("Shader option is not supported on MacOS");
|
||||
#endif // __APPLE__
|
||||
_shaderOption = gaia::ShaderOption::Billboard_VBO;
|
||||
break;
|
||||
case Parameters::ShaderOption::BillboardSSBONoFBO:
|
||||
_shaderOption = gaia::ShaderOption::Billboard_SSBO_noFBO;
|
||||
break;
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}
|
||||
_shaderOption.onChange([&]() {
|
||||
@@ -647,95 +567,34 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary)
|
||||
});
|
||||
addProperty(_shaderOption);
|
||||
|
||||
_pointSpreadFunctionTexturePath = absPath(dictionary.value<std::string>(
|
||||
PsfTextureInfo.identifier
|
||||
));
|
||||
_pointSpreadFunctionFile = std::make_unique<File>(_pointSpreadFunctionTexturePath);
|
||||
|
||||
_pointSpreadFunctionTexturePath = absPath(p.texture);
|
||||
_pointSpreadFunctionTexturePath.onChange(
|
||||
[&](){ _pointSpreadFunctionTextureIsDirty = true; }
|
||||
);
|
||||
_pointSpreadFunctionFile = std::make_unique<File>(_pointSpreadFunctionTexturePath);
|
||||
_pointSpreadFunctionFile->setCallback(
|
||||
[&](const File&) { _pointSpreadFunctionTextureIsDirty = true; }
|
||||
);
|
||||
|
||||
_colorTexturePath = absPath(dictionary.value<std::string>(
|
||||
ColorTextureInfo.identifier
|
||||
));
|
||||
_colorTexturePath = absPath(p.colorMap);
|
||||
_colorTextureFile = std::make_unique<File>(_colorTexturePath);
|
||||
_colorTexturePath.onChange([&]() { _colorTextureIsDirty = true; });
|
||||
_colorTextureFile->setCallback([&](const File&) { _colorTextureIsDirty = true; });
|
||||
|
||||
if (dictionary.hasKey(LuminosityMultiplierInfo.identifier)) {
|
||||
_luminosityMultiplier = static_cast<float>(
|
||||
dictionary.value<double>(LuminosityMultiplierInfo.identifier)
|
||||
);
|
||||
}
|
||||
_luminosityMultiplier = p.luminosityMultiplier.value_or(_luminosityMultiplier);
|
||||
_magnitudeBoost = p.magnitudeBoost.value_or(_magnitudeBoost);
|
||||
_cutOffThreshold = p.cutOffThreshold.value_or(_cutOffThreshold);
|
||||
_sharpness = p.sharpness.value_or(_sharpness);
|
||||
_billboardSize = p.billboardSize.value_or(_billboardSize);
|
||||
_closeUpBoostDist = p.closeUpBoostDist.value_or(_closeUpBoostDist);
|
||||
_tmPointFilterSize = p.filterSize.value_or(_tmPointFilterSize);
|
||||
_tmPointSigma = p.sigma.value_or(_tmPointSigma);
|
||||
_tmPointPixelWeightThreshold =
|
||||
p.pixelWeightThreshold.value_or(_tmPointPixelWeightThreshold);
|
||||
_additionalNodes = p.additionalNodes.value_or(_additionalNodes);
|
||||
_lodPixelThreshold = p.lodPixelThreshold.value_or(_lodPixelThreshold);
|
||||
|
||||
if (dictionary.hasKey(MagnitudeBoostInfo.identifier)) {
|
||||
_magnitudeBoost = static_cast<float>(
|
||||
dictionary.value<double>(MagnitudeBoostInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(CutOffThresholdInfo.identifier)) {
|
||||
_cutOffThreshold = static_cast<float>(
|
||||
dictionary.value<double>(CutOffThresholdInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(SharpnessInfo.identifier)) {
|
||||
_sharpness = static_cast<float>(
|
||||
dictionary.value<double>(SharpnessInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(BillboardSizeInfo.identifier)) {
|
||||
_billboardSize = static_cast<float>(
|
||||
dictionary.value<double>(BillboardSizeInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(CloseUpBoostDistInfo.identifier)) {
|
||||
_closeUpBoostDist = static_cast<float>(
|
||||
dictionary.value<double>(CloseUpBoostDistInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(TmPointFilterSizeInfo.identifier)) {
|
||||
_tmPointFilterSize = static_cast<int>(
|
||||
dictionary.value<double>(TmPointFilterSizeInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(TmPointSigmaInfo.identifier)) {
|
||||
_tmPointSigma = static_cast<float>(
|
||||
dictionary.value<double>(TmPointSigmaInfo.identifier)
|
||||
);
|
||||
}
|
||||
if (dictionary.hasKey(TmPointPxThresholdInfo.identifier)) {
|
||||
_tmPointPixelWeightThreshold = static_cast<float>(
|
||||
dictionary.value<double>(TmPointPxThresholdInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(AdditionalNodesInfo.identifier)) {
|
||||
_additionalNodes = static_cast<glm::ivec2>(
|
||||
dictionary.value<glm::dvec2>(AdditionalNodesInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LodPixelThresholdInfo.identifier)) {
|
||||
_lodPixelThreshold = static_cast<float>(
|
||||
dictionary.value<double>(LodPixelThresholdInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(MaxGpuMemoryPercentInfo.identifier)) {
|
||||
_maxGpuMemoryPercent = static_cast<float>(
|
||||
dictionary.value<double>(MaxGpuMemoryPercentInfo.identifier)
|
||||
);
|
||||
}
|
||||
_maxGpuMemoryPercent = p.maxGpuMemoryPercent.value_or(_maxGpuMemoryPercent);
|
||||
_maxGpuMemoryPercent.onChange([&]() {
|
||||
if (_ssboData != 0) {
|
||||
glDeleteBuffers(1, &_ssboData);
|
||||
@@ -761,59 +620,36 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary)
|
||||
_maxStreamingBudgetInBytes = 0;
|
||||
});
|
||||
|
||||
if (dictionary.hasKey(MaxCpuMemoryPercentInfo.identifier)) {
|
||||
_maxCpuMemoryPercent = static_cast<float>(
|
||||
dictionary.value<double>(MaxCpuMemoryPercentInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(FilterPosXInfo.identifier)) {
|
||||
_posXThreshold = dictionary.value<glm::dvec2>(FilterPosXInfo.identifier);
|
||||
}
|
||||
_maxCpuMemoryPercent = p.maxCpuMemoryPercent.value_or(_maxCpuMemoryPercent);
|
||||
_posXThreshold = p.filterPosX.value_or(_posXThreshold);
|
||||
addProperty(_posXThreshold);
|
||||
|
||||
if (dictionary.hasKey(FilterPosYInfo.identifier)) {
|
||||
_posXThreshold = dictionary.value<glm::dvec2>(FilterPosYInfo.identifier);
|
||||
}
|
||||
_posYThreshold = p.filterPosY.value_or(_posYThreshold);
|
||||
addProperty(_posYThreshold);
|
||||
|
||||
if (dictionary.hasKey(FilterPosZInfo.identifier)) {
|
||||
_posZThreshold = dictionary.value<glm::dvec2>(FilterPosZInfo.identifier);
|
||||
}
|
||||
_posZThreshold = p.filterPosZ.value_or(_posZThreshold);
|
||||
addProperty(_posZThreshold);
|
||||
|
||||
if (dictionary.hasKey(FilterGMagInfo.identifier)) {
|
||||
_gMagThreshold = dictionary.value<glm::dvec2>(FilterGMagInfo.identifier);
|
||||
}
|
||||
_gMagThreshold = p.filterGMag.value_or(_gMagThreshold);
|
||||
addProperty(_gMagThreshold);
|
||||
|
||||
if (dictionary.hasKey(FilterBpRpInfo.identifier)) {
|
||||
_bpRpThreshold = dictionary.value<glm::dvec2>(FilterBpRpInfo.identifier);
|
||||
}
|
||||
_bpRpThreshold = p.filterBpRp.value_or(_bpRpThreshold);
|
||||
addProperty(_bpRpThreshold);
|
||||
|
||||
if (dictionary.hasKey(FilterDistInfo.identifier)) {
|
||||
_distThreshold = dictionary.value<glm::dvec2>(FilterDistInfo.identifier);
|
||||
}
|
||||
_distThreshold = p.filterDist.value_or(_distThreshold);
|
||||
addProperty(_distThreshold);
|
||||
|
||||
// Only add properties correlated to fits files if we're reading from a fits file.
|
||||
if (_fileReaderOption == gaia::FileReaderOption::Fits) {
|
||||
if (dictionary.hasKey(FirstRowInfo.identifier)) {
|
||||
_firstRow = static_cast<int>(
|
||||
dictionary.value<double>(FirstRowInfo.identifier)
|
||||
);
|
||||
}
|
||||
_firstRow = p.firstRow.value_or(_firstRow);
|
||||
_firstRow.onChange([&]() { _dataIsDirty = true; });
|
||||
addProperty(_firstRow);
|
||||
|
||||
if (dictionary.hasKey(LastRowInfo.identifier)) {
|
||||
_lastRow = static_cast<int>(dictionary.value<double>(LastRowInfo.identifier));
|
||||
}
|
||||
_lastRow = p.lastRow.value_or(_lastRow);
|
||||
_lastRow.onChange([&]() { _dataIsDirty = true; });
|
||||
addProperty(_lastRow);
|
||||
|
||||
if (dictionary.hasKey(ColumnNamesInfo.identifier)) {
|
||||
if (p.columnNames.has_value()) {
|
||||
ghoul::Dictionary tmpDict = dictionary.value<ghoul::Dictionary>(
|
||||
ColumnNamesInfo.identifier
|
||||
);
|
||||
@@ -834,13 +670,11 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary)
|
||||
}
|
||||
|
||||
if (_firstRow > _lastRow) {
|
||||
throw ghoul::RuntimeError("User defined FirstRow is bigger than LastRow.");
|
||||
throw ghoul::RuntimeError("User defined FirstRow is bigger than LastRow");
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(ReportGlErrorsInfo.identifier)) {
|
||||
_reportGlErrors = dictionary.value<bool>(ReportGlErrorsInfo.identifier);
|
||||
}
|
||||
_reportGlErrors = p.reportGlErrors.value_or(_reportGlErrors);
|
||||
addProperty(_reportGlErrors);
|
||||
|
||||
// Add a read-only property for the number of rendered stars per frame.
|
||||
|
||||
@@ -35,164 +35,263 @@
|
||||
#include <thread>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyInFileOrFolderPath = "InFileOrFolderPath";
|
||||
constexpr const char* KeyOutFileOrFolderPath = "OutFileOrFolderPath";
|
||||
constexpr const char* KeyMaxDist = "MaxDist";
|
||||
constexpr const char* KeyMaxStarsPerNode = "MaxStarsPerNode";
|
||||
constexpr const char* KeySingleFileInput = "SingleFileInput";
|
||||
|
||||
constexpr const char* KeyFilterPosX = "FilterPosX";
|
||||
constexpr const char* KeyFilterPosY = "FilterPosY";
|
||||
constexpr const char* KeyFilterPosZ = "FilterPosZ";
|
||||
constexpr const char* KeyFilterGMag = "FilterGMag";
|
||||
constexpr const char* KeyFilterBpRp = "FilterBpRp";
|
||||
constexpr const char* KeyFilterVelX = "FilterVelX";
|
||||
constexpr const char* KeyFilterVelY = "FilterVelY";
|
||||
constexpr const char* KeyFilterVelZ = "FilterVelZ";
|
||||
constexpr const char* KeyFilterBpMag = "FilterBpMag";
|
||||
constexpr const char* KeyFilterRpMag = "FilterRpMag";
|
||||
constexpr const char* KeyFilterBpG = "FilterBpG";
|
||||
constexpr const char* KeyFilterGRp = "FilterGRp";
|
||||
constexpr const char* KeyFilterRa = "FilterRa";
|
||||
constexpr const char* KeyFilterRaError = "FilterRaError";
|
||||
constexpr const char* KeyFilterDec = "FilterDec";
|
||||
constexpr const char* KeyFilterDecError = "FilterDecError";
|
||||
constexpr const char* KeyFilterParallax = "FilterParallax";
|
||||
constexpr const char* KeyFilterParallaxError = "FilterParallaxError";
|
||||
constexpr const char* KeyFilterPmra = "FilterPmra";
|
||||
constexpr const char* KeyFilterPmraError = "FilterPmraError";
|
||||
constexpr const char* KeyFilterPmdec = "FilterPmdec";
|
||||
constexpr const char* KeyFilterPmdecError = "FilterPmdecError";
|
||||
constexpr const char* KeyFilterRv = "FilterRv";
|
||||
constexpr const char* KeyFilterRvError = "FilterRvError";
|
||||
|
||||
constexpr const char* _loggerCat = "ConstructOctreeTask";
|
||||
|
||||
struct [[codegen::Dictionary(ConstructOctreeTask)]] Parameters {
|
||||
// If SingleFileInput is set to true then this specifies the path to a single BIN
|
||||
// file containing a full dataset. Otherwise this specifies the path to a folder
|
||||
// with multiple BIN files containing subsets of sorted star data
|
||||
std::string inFileOrFolderPath;
|
||||
|
||||
// If SingleFileInput is set to true then this specifies the output file name
|
||||
// (including full path). Otherwise this specifies the path to the folder which to
|
||||
// save all files
|
||||
std::string outFileOrFolderPath;
|
||||
|
||||
// If set it determines what MAX_DIST to use when creating Octree
|
||||
std::optional<int> maxDist;
|
||||
|
||||
// If set it determines what MAX_STAR_PER_NODE to use when creating Octree
|
||||
std::optional<int> maxStarsPerNode;
|
||||
|
||||
// If true then task will read from a single file and output a single binary file
|
||||
// with the full Octree. If false then task will read all files in specified
|
||||
// folder and output multiple files for the Octree
|
||||
std::optional<bool> singleFileInput;
|
||||
|
||||
// If defined then only stars with Position X values between [min, max] will be
|
||||
// inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to
|
||||
// 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterPosX;
|
||||
|
||||
// If defined then only stars with Position Y values between [min, max] will be
|
||||
// inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to
|
||||
// 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterPosY;
|
||||
|
||||
// If defined then only stars with Position Z values between [min, max] will be
|
||||
// inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to
|
||||
// 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterPosZ;
|
||||
|
||||
// If defined then only stars with G mean magnitude values between [min, max] will
|
||||
// be inserted into Octree (if min is set to 20.0 it is read as -Inf, if max is
|
||||
// set to 20.0 it is read as +Inf). If min = max then all values equal min|max
|
||||
// will be filtered away. Default GMag = 20.0 if no value existed
|
||||
std::optional<glm::vec2> filterGMag;
|
||||
|
||||
// If defined then only stars with Bp-Rp color values between [min, max] will be
|
||||
// inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to
|
||||
// 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterBpRp;
|
||||
|
||||
// If defined then only stars with Velocity X values between [min, max] will be
|
||||
// inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to
|
||||
// 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterVelX;
|
||||
|
||||
// If defined then only stars with Velocity Y values between [min, max] will be
|
||||
// inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to
|
||||
// 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterVelY;
|
||||
|
||||
// If defined then only stars with Velocity Z values between [min, max] will be
|
||||
// inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to
|
||||
// 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterVelZ;
|
||||
|
||||
// If defined then only stars with Bp mean magnitude values between [min, max]
|
||||
// will be inserted into Octree (if min is set to 20.0 it is read as -Inf, if max
|
||||
// is set to 20.0 it is read as +Inf). If min = max then all values equal min|max
|
||||
// will be filtered away. Default BpMag = 20.0 if no value existed
|
||||
std::optional<glm::vec2> filterBpMag;
|
||||
|
||||
// If defined then only stars with Rp mean magnitude values between [min, max]
|
||||
// will be inserted into Octree (if min is set to 20.0 it is read as -Inf, if max
|
||||
// is set to 20.0 it is read as +Inf). If min = max then all values equal min|max
|
||||
// will be filtered away. Default RpMag = 20.0 if no value existed
|
||||
std::optional<glm::vec2> filterRpMag;
|
||||
|
||||
// If defined then only stars with Bp-G color values between [min, max] will be
|
||||
// inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to
|
||||
// 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterBpG;
|
||||
|
||||
// If defined then only stars with G-Rp color values between [min, max] will be
|
||||
// inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to
|
||||
// 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterGRp;
|
||||
|
||||
// If defined then only stars with RA values between [min, max] will be inserted
|
||||
// into Octree (if min is set to 0.0 it is read as -Inf, if max is set to 0.0 it
|
||||
// is read as +Inf). If min = max then all values equal min|max will be filtered
|
||||
// away
|
||||
std::optional<glm::vec2> filterRa;
|
||||
|
||||
// If defined then only stars with RA Error values between [min, max] will be
|
||||
// inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to
|
||||
// 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterRaError;
|
||||
|
||||
// If defined then only stars with DEC values between [min, max] will be inserted
|
||||
// into Octree (if min is set to 0.0 it is read as -Inf, if max is set to 0.0 it
|
||||
// is read as +Inf). If min = max then all values equal min|max will be filtered
|
||||
// away
|
||||
std::optional<glm::vec2> filterDec;
|
||||
|
||||
// If defined then only stars with DEC Error values between [min, max] will be
|
||||
// inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to
|
||||
// 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterDecError;
|
||||
|
||||
// If defined then only stars with Parallax values between [min, max] will be
|
||||
// inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to
|
||||
// 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterParallax;
|
||||
|
||||
// If defined then only stars with Parallax Error values between [min, max] will
|
||||
// be inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set
|
||||
// to 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterParallaxError;
|
||||
|
||||
// If defined then only stars with Proper Motion RA values between [min, max] will
|
||||
// be inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set
|
||||
// to 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterPmra;
|
||||
|
||||
// If defined then only stars with Proper Motion RA Error values between
|
||||
// [min, max] will be inserted into Octree (if min is set to 0.0 it is read as
|
||||
// -Inf, if max is set to 0.0 it is read as +Inf). If min = max then all values
|
||||
// equal min|max will be filtered away
|
||||
std::optional<glm::vec2> filterPmraError;
|
||||
|
||||
// If defined then only stars with Proper Motion DEC values between [min, max]
|
||||
// will be inserted into Octree (if min is set to 0.0 it is read as -Inf, if max
|
||||
// is set to 0.0 it is read as +Inf). If min = max then all values equal min|max
|
||||
// will be filtered away
|
||||
std::optional<glm::vec2> filterPmdec;
|
||||
|
||||
// If defined then only stars with Proper Motion DEC Error values between
|
||||
// [min, max] will be inserted into Octree (if min is set to 0.0 it is read as
|
||||
// -Inf, if max is set to 0.0 it is read as +Inf). If min = max then all values
|
||||
// equal min|max will be filtered away
|
||||
std::optional<glm::vec2> filterPmdecError;
|
||||
|
||||
// If defined then only stars with Radial Velocity values between [min, max] will
|
||||
// be inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set
|
||||
// to 0.0 it is read as +Inf). If min = max then all values equal min|max will be
|
||||
// filtered away
|
||||
std::optional<glm::vec2> filterRv;
|
||||
|
||||
// If defined then only stars with Radial Velocity Error values between [min, max]
|
||||
// will be inserted into Octree (if min is set to 0.0 it is read as -Inf, if max
|
||||
// is set to 0.0 it is read as +Inf). If min = max then all values equal min|max
|
||||
// will be filtered away
|
||||
std::optional<glm::vec2> filterRvError;
|
||||
};
|
||||
#include "constructoctreetask_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
ConstructOctreeTask::ConstructOctreeTask(const ghoul::Dictionary& dictionary) {
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
documentation(),
|
||||
dictionary,
|
||||
"ConstructOctreeTask"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_inFileOrFolderPath = absPath(dictionary.value<std::string>(KeyInFileOrFolderPath));
|
||||
_outFileOrFolderPath = absPath(dictionary.value<std::string>(KeyOutFileOrFolderPath));
|
||||
|
||||
if (dictionary.hasKey(KeyMaxDist)) {
|
||||
_maxDist = static_cast<int>(dictionary.value<double>(KeyMaxDist));
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyMaxStarsPerNode)) {
|
||||
_maxStarsPerNode = static_cast<int>(dictionary.value<double>(KeyMaxStarsPerNode));
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeySingleFileInput)) {
|
||||
_singleFileInput = dictionary.value<bool>(KeySingleFileInput);
|
||||
}
|
||||
_inFileOrFolderPath = absPath(p.inFileOrFolderPath);
|
||||
_outFileOrFolderPath = absPath(p.outFileOrFolderPath);
|
||||
_maxDist = p.maxDist.value_or(_maxDist);
|
||||
_maxStarsPerNode = p.maxStarsPerNode.value_or(_maxStarsPerNode);
|
||||
_singleFileInput = p.singleFileInput.value_or(_singleFileInput);
|
||||
|
||||
_octreeManager = std::make_shared<OctreeManager>();
|
||||
_indexOctreeManager = std::make_shared<OctreeManager>();
|
||||
|
||||
// Check for filter params.
|
||||
if (dictionary.hasKey(KeyFilterPosX)) {
|
||||
_posX = dictionary.value<glm::dvec2>(KeyFilterPosX);
|
||||
_filterPosX = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterPosY)) {
|
||||
_posY = dictionary.value<glm::dvec2>(KeyFilterPosY);
|
||||
_filterPosY = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterPosZ)) {
|
||||
_posZ = dictionary.value<glm::dvec2>(KeyFilterPosZ);
|
||||
_filterPosZ = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterGMag)) {
|
||||
_gMag = dictionary.value<glm::dvec2>(KeyFilterGMag);
|
||||
_filterGMag = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterBpRp)) {
|
||||
_bpRp = dictionary.value<glm::dvec2>(KeyFilterBpRp);
|
||||
_filterBpRp = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterVelX)) {
|
||||
_velX = dictionary.value<glm::dvec2>(KeyFilterVelX);
|
||||
_filterVelX = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterVelY)) {
|
||||
_velY = dictionary.value<glm::dvec2>(KeyFilterVelY);
|
||||
_filterVelY = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterVelZ)) {
|
||||
_velZ = dictionary.value<glm::dvec2>(KeyFilterVelZ);
|
||||
_filterVelZ = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterBpMag)) {
|
||||
_bpMag = dictionary.value<glm::dvec2>(KeyFilterBpMag);
|
||||
_filterBpMag = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterRpMag)) {
|
||||
_rpMag = dictionary.value<glm::dvec2>(KeyFilterRpMag);
|
||||
_filterRpMag = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterBpG)) {
|
||||
_bpG = dictionary.value<glm::dvec2>(KeyFilterBpG);
|
||||
_filterBpG = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterGRp)) {
|
||||
_gRp = dictionary.value<glm::dvec2>(KeyFilterGRp);
|
||||
_filterGRp = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterRa)) {
|
||||
_ra = dictionary.value<glm::dvec2>(KeyFilterRa);
|
||||
_filterRa = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterRaError)) {
|
||||
_raError = dictionary.value<glm::dvec2>(KeyFilterRaError);
|
||||
_filterRaError = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterDec)) {
|
||||
_dec = dictionary.value<glm::dvec2>(KeyFilterDec);
|
||||
_filterDec = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterDecError)) {
|
||||
_decError = dictionary.value<glm::dvec2>(KeyFilterDecError);
|
||||
_filterDecError = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterParallax)) {
|
||||
_parallax = dictionary.value<glm::dvec2>(KeyFilterParallax);
|
||||
_filterParallax = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterParallaxError)) {
|
||||
_parallaxError = dictionary.value<glm::dvec2>(KeyFilterParallaxError);
|
||||
_filterParallaxError = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterPmra)) {
|
||||
_pmra = dictionary.value<glm::dvec2>(KeyFilterPmra);
|
||||
_filterPmra = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterPmraError)) {
|
||||
_pmraError = dictionary.value<glm::dvec2>(KeyFilterPmraError);
|
||||
_filterPmraError = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterPmdec)) {
|
||||
_pmdec = dictionary.value<glm::dvec2>(KeyFilterPmdec);
|
||||
_filterPmdec = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterPmdecError)) {
|
||||
_pmdecError = dictionary.value<glm::dvec2>(KeyFilterPmdecError);
|
||||
_filterPmdecError = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterRv)) {
|
||||
_rv = dictionary.value<glm::dvec2>(KeyFilterRv);
|
||||
_filterRv = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterRvError)) {
|
||||
_rvError = dictionary.value<glm::dvec2>(KeyFilterRvError);
|
||||
_filterRvError = true;
|
||||
}
|
||||
|
||||
_posX = p.filterPosX.value_or(_posX);
|
||||
_filterPosX = p.filterPosX.has_value();
|
||||
|
||||
_posY = p.filterPosY.value_or(_posY);
|
||||
_filterPosY = p.filterPosY.has_value();
|
||||
|
||||
_posZ = p.filterPosZ.value_or(_posZ);
|
||||
_filterPosZ = p.filterPosZ.has_value();
|
||||
|
||||
_gMag = p.filterGMag.value_or(_gMag);
|
||||
_filterGMag = p.filterGMag.has_value();
|
||||
|
||||
_bpRp = p.filterBpRp.value_or(_bpRp);
|
||||
_filterBpRp = p.filterBpRp.has_value();
|
||||
|
||||
_velX = p.filterVelX.value_or(_velX);
|
||||
_filterVelX = p.filterVelX.has_value();
|
||||
|
||||
_velY = p.filterVelY.value_or(_velY);
|
||||
_filterVelY = p.filterVelY.has_value();
|
||||
|
||||
_velZ = p.filterVelZ.value_or(_velZ);
|
||||
_filterVelZ = p.filterVelZ.has_value();
|
||||
|
||||
_bpMag = p.filterBpMag.value_or(_bpMag);
|
||||
_filterBpMag = p.filterBpMag.has_value();
|
||||
|
||||
_rpMag = p.filterRpMag.value_or(_rpMag);
|
||||
_filterRpMag = p.filterRpMag.has_value();
|
||||
|
||||
_bpG = p.filterBpG.value_or(_bpG);
|
||||
_filterBpG = p.filterBpG.has_value();
|
||||
|
||||
_gRp = p.filterGRp.value_or(_gRp);
|
||||
_filterGRp = p.filterGRp.has_value();
|
||||
|
||||
_ra = p.filterRa.value_or(_ra);
|
||||
_filterRa = p.filterRa.has_value();
|
||||
|
||||
_raError = p.filterRaError.value_or(_raError);
|
||||
_filterRaError = p.filterRaError.has_value();
|
||||
|
||||
_dec = p.filterDec.value_or(_dec);
|
||||
_filterDec = p.filterDec.has_value();
|
||||
|
||||
_decError = p.filterDecError.value_or(_decError);
|
||||
_filterDecError = p.filterDecError.has_value();
|
||||
|
||||
_parallax = p.filterParallax.value_or(_parallax);
|
||||
_filterParallax = p.filterParallax.has_value();
|
||||
|
||||
_parallaxError = p.filterParallaxError.value_or(_parallaxError);
|
||||
_filterParallaxError = p.filterParallaxError.has_value();
|
||||
|
||||
_pmra = p.filterPmra.value_or(_pmra);
|
||||
_filterPmra = p.filterPmra.has_value();
|
||||
|
||||
_pmraError = p.filterPmraError.value_or(_pmraError);
|
||||
_filterPmraError = p.filterPmraError.has_value();
|
||||
|
||||
_pmdec = p.filterPmdec.value_or(_pmdec);
|
||||
_filterPmdec = p.filterPmdec.has_value();
|
||||
|
||||
_pmdecError = p.filterPmdecError.value_or(_pmdecError);
|
||||
_filterPmdecError = p.filterPmdecError.has_value();
|
||||
|
||||
_rv = p.filterRv.value_or(_rv);
|
||||
_filterRv = p.filterRv.has_value();
|
||||
|
||||
_rvError = p.filterRvError.value_or(_rvError);
|
||||
_filterRvError = p.filterRvError.has_value();
|
||||
}
|
||||
|
||||
std::string ConstructOctreeTask::description() {
|
||||
@@ -201,7 +300,7 @@ std::string ConstructOctreeTask::description() {
|
||||
}
|
||||
|
||||
void ConstructOctreeTask::perform(const Task::ProgressCallback& onProgress) {
|
||||
onProgress(0.0f);
|
||||
onProgress(0.f);
|
||||
|
||||
if (_singleFileInput) {
|
||||
constructOctreeFromSingleFile(onProgress);
|
||||
@@ -210,7 +309,7 @@ void ConstructOctreeTask::perform(const Task::ProgressCallback& onProgress) {
|
||||
constructOctreeFromFolder(onProgress);
|
||||
}
|
||||
|
||||
onProgress(1.0f);
|
||||
onProgress(1.f);
|
||||
}
|
||||
|
||||
void ConstructOctreeTask::constructOctreeFromSingleFile(
|
||||
@@ -543,269 +642,9 @@ bool ConstructOctreeTask::filterStar(const glm::vec2& range, float filterValue,
|
||||
}
|
||||
|
||||
documentation::Documentation ConstructOctreeTask::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"ConstructOctreeTask",
|
||||
"gaiamission_constructoctreefrombin",
|
||||
{
|
||||
{
|
||||
KeyInFileOrFolderPath,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"If SingleFileInput is set to true then this specifies the path to a "
|
||||
"single BIN file containing a full dataset. Otherwise this specifies the "
|
||||
"path to a folder with multiple BIN files containing subsets of sorted "
|
||||
"star data.",
|
||||
},
|
||||
{
|
||||
KeyOutFileOrFolderPath,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"If SingleFileInput is set to true then this specifies the output file "
|
||||
"name (including full path). Otherwise this specifies the path to the "
|
||||
"folder which to save all files.",
|
||||
},
|
||||
{
|
||||
KeyMaxDist,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
"If set it determines what MAX_DIST to use when creating Octree."
|
||||
},
|
||||
{
|
||||
KeyMaxStarsPerNode,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
"If set it determines what MAX_STAR_PER_NODE to use when creating Octree."
|
||||
},
|
||||
{
|
||||
KeySingleFileInput,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
"If true then task will read from a single file and output a single "
|
||||
"binary file with the full Octree. If false then task will read all "
|
||||
"files in specified folder and output multiple files for the Octree."
|
||||
},
|
||||
{
|
||||
KeyFilterPosX,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Position X values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterPosY,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Position Y values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterPosZ,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Position Z values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterGMag,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with G mean magnitude values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 20.0 it is "
|
||||
"read as -Inf, if max is set to 20.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away. Default "
|
||||
"GMag = 20.0 if no value existed."
|
||||
},
|
||||
{
|
||||
KeyFilterBpRp,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Bp-Rp color values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterVelX,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Velocity X values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterVelY,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Velocity Y values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterVelZ,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Velocity Z values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterBpMag,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Bp mean magnitude values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 20.0 it is "
|
||||
"read as -Inf, if max is set to 20.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away. Default "
|
||||
"BpMag = 20.0 if no value existed."
|
||||
},
|
||||
{
|
||||
KeyFilterRpMag,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Rp mean magnitude values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 20.0 it is "
|
||||
"read as -Inf, if max is set to 20.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away. Default RpMag = "
|
||||
"20.0 if no value existed."
|
||||
},
|
||||
{
|
||||
KeyFilterBpG,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Bp-G color values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterGRp,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with G-Rp color values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterRa,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with RA values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterRaError,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with RA Error values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterDec,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with DEC values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterDecError,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with DEC Error values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterParallax,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Parallax values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterParallaxError,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Parallax Error values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterPmra,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Proper Motion RA values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterPmraError,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Proper Motion RA Error values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterPmdec,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Proper Motion DEC values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterPmdecError,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Proper Motion DEC Error values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterRv,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Radial Velocity values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterRvError,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Radial Velocity Error values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "gaiamission_constructoctreefrombin";
|
||||
return doc;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -36,55 +36,61 @@
|
||||
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
#include <optional>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyInFileOrFolderPath = "InFileOrFolderPath";
|
||||
constexpr const char* KeyOutFileOrFolderPath = "OutFileOrFolderPath";
|
||||
constexpr const char* KeySingleFileProcess = "SingleFileProcess";
|
||||
constexpr const char* KeyThreadsToUse = "ThreadsToUse";
|
||||
constexpr const char* KeyFirstRow = "FirstRow";
|
||||
constexpr const char* KeyLastRow = "LastRow";
|
||||
constexpr const char* KeyFilterColumnNames = "FilterColumnNames";
|
||||
|
||||
constexpr const char* _loggerCat = "ReadFitsTask";
|
||||
|
||||
struct [[codegen::Dictionary(ReadFitsTask)]] Parameters {
|
||||
// If SingleFileProcess is set to true then this specifies the path to a single
|
||||
// FITS file that will be read. Otherwise it specifies the path to a folder with
|
||||
// multiple FITS files that are to be read
|
||||
std::string inFileOrFolderPath;
|
||||
|
||||
// If SingleFileProcess is set to true then this specifies the name (including
|
||||
// entire path) to the output file. Otherwise it specifies the path to the output
|
||||
// folder which to export binary star data to
|
||||
std::string outFileOrFolderPath;
|
||||
|
||||
// If true then task will read from a single FITS file and output a single binary
|
||||
// file. If false then task will read all files in specified folder and output
|
||||
// multiple files sorted by location
|
||||
std::optional<bool> singleFileProcess;
|
||||
|
||||
// Defines how many threads to use when reading from multiple files
|
||||
std::optional<int> threadsToUse [[codegen::greater(1)]];
|
||||
|
||||
// Defines the first row that will be read from the specified FITS file(s). If not
|
||||
// defined then reading will start at first row
|
||||
std::optional<int> firstRow;
|
||||
|
||||
// Defines the last row that will be read from the specified FITS file(s). If not
|
||||
// defined (or less than FirstRow) then full file(s) will be read
|
||||
std::optional<int> lastRow;
|
||||
|
||||
// A list of strings with the names of all the additional columns that are to be
|
||||
// read from the specified FITS file(s). These columns can be used for filtering
|
||||
// while constructing Octree later
|
||||
std::optional<std::vector<std::string>> filterColumnNames;
|
||||
};
|
||||
#include "readfitstask_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
ReadFitsTask::ReadFitsTask(const ghoul::Dictionary& dictionary) {
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
documentation(),
|
||||
dictionary,
|
||||
"ReadFitsTask"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_inFileOrFolderPath = absPath(dictionary.value<std::string>(KeyInFileOrFolderPath));
|
||||
_outFileOrFolderPath = absPath(dictionary.value<std::string>(KeyOutFileOrFolderPath));
|
||||
_inFileOrFolderPath = absPath(p.inFileOrFolderPath);
|
||||
_outFileOrFolderPath = absPath(p.outFileOrFolderPath);
|
||||
_singleFileProcess = p.singleFileProcess.value_or(_singleFileProcess);
|
||||
_threadsToUse = p.threadsToUse.value_or(_threadsToUse);
|
||||
_firstRow = p.firstRow.value_or(_firstRow);
|
||||
_lastRow = p.lastRow.value_or(_lastRow);
|
||||
|
||||
if (dictionary.hasKey(KeySingleFileProcess)) {
|
||||
_singleFileProcess = dictionary.value<bool>(KeySingleFileProcess);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyThreadsToUse)) {
|
||||
_threadsToUse = static_cast<size_t>(dictionary.value<double>(KeyThreadsToUse));
|
||||
if (_threadsToUse < 1) {
|
||||
LINFO(fmt::format(
|
||||
"User defined ThreadsToUse was: {}. Will be set to 1", _threadsToUse
|
||||
));
|
||||
_threadsToUse = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyFirstRow)) {
|
||||
_firstRow = static_cast<int>(dictionary.value<double>(KeyFirstRow));
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyLastRow)) {
|
||||
_lastRow = static_cast<int>(dictionary.value<double>(KeyLastRow));
|
||||
}
|
||||
|
||||
|
||||
if (dictionary.hasKey(KeyFilterColumnNames)) {
|
||||
if (p.filterColumnNames.has_value()) {
|
||||
ghoul::Dictionary d = dictionary.value<ghoul::Dictionary>(KeyFilterColumnNames);
|
||||
|
||||
// Ugly fix for ASCII sorting when there are more columns read than 10.
|
||||
@@ -322,66 +328,9 @@ int ReadFitsTask::writeOctantToFile(const std::vector<float>& octantData, int in
|
||||
}
|
||||
|
||||
documentation::Documentation ReadFitsTask::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"ReadFitsFile",
|
||||
"gaiamission_fitsfiletorawdata",
|
||||
{
|
||||
{
|
||||
KeyInFileOrFolderPath,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"If SingleFileProcess is set to true then this specifies the path to a "
|
||||
"single FITS file that will be read. Otherwise it specifies the path to "
|
||||
"a folder with multiple FITS files that are to be read.",
|
||||
},
|
||||
{
|
||||
KeyOutFileOrFolderPath,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"If SingleFileProcess is set to true then this specifies the name "
|
||||
"(including entire path) to the output file. Otherwise it specifies the "
|
||||
"path to the output folder which to export binary star data to.",
|
||||
},
|
||||
{
|
||||
KeySingleFileProcess,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
"If true then task will read from a single FITS file and output a single "
|
||||
"binary file. If false then task will read all files in specified folder "
|
||||
"and output multiple files sorted by location."
|
||||
},
|
||||
{
|
||||
KeyThreadsToUse,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
"Defines how many threads to use when reading from multiple files."
|
||||
},
|
||||
{
|
||||
KeyFirstRow,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
"Defines the first row that will be read from the specified FITS "
|
||||
"file(s). If not defined then reading will start at first row.",
|
||||
},
|
||||
{
|
||||
KeyLastRow,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
"Defines the last row that will be read from the specified FITS file(s). "
|
||||
"If not defined (or less than FirstRow) then full file(s) will be read.",
|
||||
},
|
||||
{
|
||||
KeyFilterColumnNames,
|
||||
new StringListVerifier,
|
||||
Optional::Yes,
|
||||
"A list of strings with the names of all the additional columns that are "
|
||||
"to be read from the specified FITS file(s). These columns can be used "
|
||||
"for filtering while constructing Octree later.",
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "gaiamission_fitsfiletorawdata";
|
||||
return doc;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -34,23 +34,30 @@
|
||||
#include <fstream>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyInFilePath = "InFilePath";
|
||||
constexpr const char* KeyOutFilePath = "OutFilePath";
|
||||
|
||||
constexpr const char* _loggerCat = "ReadSpeckTask";
|
||||
|
||||
struct [[codegen::Dictionary(ReadSpeckTask)]] Parameters {
|
||||
// The path to the SPECK file that are to be read
|
||||
std::string inFilePath;
|
||||
|
||||
// The path to the file to export raw VBO data to
|
||||
std::string outFilePath;
|
||||
};
|
||||
#include "readspecktask_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
ReadSpeckTask::ReadSpeckTask(const ghoul::Dictionary& dictionary) {
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
documentation(),
|
||||
dictionary,
|
||||
"ReadSpeckTask"
|
||||
);
|
||||
documentation::Documentation ReadSpeckTask::Documentation() {
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "gaiamission_speckfiletorawdata";
|
||||
return doc;
|
||||
}
|
||||
|
||||
_inFilePath = absPath(dictionary.value<std::string>(KeyInFilePath));
|
||||
_outFilePath = absPath(dictionary.value<std::string>(KeyOutFilePath));
|
||||
ReadSpeckTask::ReadSpeckTask(const ghoul::Dictionary& dictionary) {
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
_inFilePath = absPath(p.inFilePath);
|
||||
_outFilePath = absPath(p.outFilePath);
|
||||
}
|
||||
|
||||
std::string ReadSpeckTask::description() {
|
||||
@@ -92,26 +99,4 @@ void ReadSpeckTask::perform(const Task::ProgressCallback& onProgress) {
|
||||
onProgress(1.f);
|
||||
}
|
||||
|
||||
documentation::Documentation ReadSpeckTask::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"ReadSpeckTask",
|
||||
"gaiamission_speckfiletorawdata",
|
||||
{
|
||||
{
|
||||
KeyInFilePath,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The path to the SPECK file that are to be read.",
|
||||
},
|
||||
{
|
||||
KeyOutFilePath,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The path to the file to export raw VBO data to.",
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -453,7 +453,9 @@ std::vector<documentation::Documentation> GlobeBrowsingModule::documentations()
|
||||
globebrowsing::Layer::Documentation(),
|
||||
globebrowsing::LayerAdjustment::Documentation(),
|
||||
globebrowsing::LayerManager::Documentation(),
|
||||
GlobeLabelsComponent::Documentation()
|
||||
GlobeLabelsComponent::Documentation(),
|
||||
RingsComponent::Documentation(),
|
||||
ShadowComponent::Documentation()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -62,36 +62,25 @@ namespace {
|
||||
"Determines the number of significant digits that are shown in the location text."
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(DashboardItemGlobeLocation)]] Parameters {
|
||||
// [[codegen::verbatim(FontNameInfo.description)]]
|
||||
std::optional<std::string> fontName;
|
||||
|
||||
// [[codegen::verbatim(FontSizeInfo.description)]]
|
||||
std::optional<float> fontSize;
|
||||
|
||||
// [[codegen::verbatim(SignificantDigitsInfo.description)]]
|
||||
std::optional<int> significantDigits;
|
||||
};
|
||||
#include "dashboarditemglobelocation_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation DashboardItemGlobeLocation::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"DashboardItem Globe Location",
|
||||
"globebrowsing_dashboarditem_globelocation",
|
||||
{
|
||||
{
|
||||
FontNameInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
FontNameInfo.description
|
||||
},
|
||||
{
|
||||
FontSizeInfo.identifier,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
FontSizeInfo.description
|
||||
},
|
||||
{
|
||||
SignificantDigitsInfo.identifier,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
SignificantDigitsInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "globebrowsing_dashboarditem_globelocation";
|
||||
return doc;
|
||||
}
|
||||
|
||||
DashboardItemGlobeLocation::DashboardItemGlobeLocation(
|
||||
@@ -102,30 +91,15 @@ DashboardItemGlobeLocation::DashboardItemGlobeLocation(
|
||||
, _significantDigits(SignificantDigitsInfo, 4, 1, 12)
|
||||
, _font(global::fontManager->font(KeyFontMono, 10))
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"DashboardItemGlobeLocation"
|
||||
);
|
||||
|
||||
if (dictionary.hasKey(FontNameInfo.identifier)) {
|
||||
_fontName = dictionary.value<std::string>(FontNameInfo.identifier);
|
||||
}
|
||||
if (dictionary.hasKey(FontSizeInfo.identifier)) {
|
||||
_fontSize = static_cast<float>(dictionary.value<double>(FontSizeInfo.identifier));
|
||||
}
|
||||
if (dictionary.hasKey(SignificantDigitsInfo.identifier)) {
|
||||
_significantDigits = static_cast<int>(
|
||||
dictionary.value<double>(SignificantDigitsInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_fontName = p.fontName.value_or(_fontName);
|
||||
_fontName.onChange([this]() {
|
||||
_font = global::fontManager->font(_fontName, _fontSize);
|
||||
});
|
||||
addProperty(_fontName);
|
||||
|
||||
_fontSize = p.fontSize.value_or(_fontSize);
|
||||
_fontSize.onChange([this]() {
|
||||
_font = global::fontManager->font(_fontName, _fontSize);
|
||||
});
|
||||
@@ -139,6 +113,7 @@ DashboardItemGlobeLocation::DashboardItemGlobeLocation(
|
||||
_significantDigits.value()
|
||||
);
|
||||
};
|
||||
_significantDigits = p.significantDigits.value_or(_significantDigits);
|
||||
_significantDigits.onChange(updateFormatString);
|
||||
addProperty(_significantDigits);
|
||||
updateFormatString();
|
||||
|
||||
@@ -42,14 +42,14 @@
|
||||
#include <ghoul/misc/profiling.h>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <locale>
|
||||
#include <optional>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "GlobeLabels";
|
||||
|
||||
constexpr const char* KeyLabelsFileName = "FileName";
|
||||
|
||||
constexpr const double LabelFadeOutLimitAltitudeMeters = 25000.0;
|
||||
constexpr const double RangeAngularCoefConst = 0.8;
|
||||
constexpr const float MinOpacityValueConst = 0.009f;
|
||||
@@ -163,114 +163,72 @@ namespace {
|
||||
"Label Alignment Option",
|
||||
"Labels are aligned horizontally or circularly related to the planet."
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(GlobeLabelsComponent)]] Parameters {
|
||||
// The path to the labels file
|
||||
std::optional<std::filesystem::path> fileName;
|
||||
|
||||
// [[codegen::verbatim(LabelsInfo.description)]]
|
||||
std::optional<bool> labels;
|
||||
|
||||
// [[codegen::verbatim(LabelsEnableInfo.description)]]
|
||||
std::optional<bool> enable;
|
||||
|
||||
// [[codegen::verbatim(LabelsFontSizeInfo.description)]]
|
||||
std::optional<float> labelsFontSize;
|
||||
|
||||
// [[codegen::verbatim(LabelsMinSizeInfo.description)]]
|
||||
std::optional<int> labelsMinSize;
|
||||
|
||||
// [[codegen::verbatim(LabelsMaxSizeInfo.description)]]
|
||||
std::optional<int> labelsMaxSize;
|
||||
|
||||
// [[codegen::verbatim(LabelsSizeInfo.description)]]
|
||||
std::optional<float> labelsSize;
|
||||
|
||||
// [[codegen::verbatim(LabelsMinHeightInfo.description)]]
|
||||
std::optional<float> labelsMinHeight;
|
||||
|
||||
// [[codegen::verbatim(LabelsColorInfo.description)]]
|
||||
std::optional<glm::vec3> labelsColor [[codegen::color()]];
|
||||
|
||||
// [[codegen::verbatim(LabelsOpacityInfo.description)]]
|
||||
std::optional<float> labelsOpacity [[codegen::inrange(0.f, 1.0)]];
|
||||
|
||||
// [[codegen::verbatim(LabelsFadeInStartingDistanceInfo.description)]]
|
||||
std::optional<float> fadeInStartingDistance;
|
||||
|
||||
// [[codegen::verbatim(LabelsFadeOutStartingDistanceInfo.description)]]
|
||||
std::optional<float> fadeOutStartingDistance;
|
||||
|
||||
// [[codegen::verbatim(LabelsFadeInEnabledInfo.description)]]
|
||||
std::optional<bool> labelsFadeInEnabled;
|
||||
|
||||
// [[codegen::verbatim(LabelsFadeOutEnabledInfo.description)]]
|
||||
std::optional<bool> labelsFadeOutEnabled;
|
||||
|
||||
// [[codegen::verbatim(LabelsDisableCullingEnabledInfo.description)]]
|
||||
std::optional<bool> labelsDisableCullingEnabled;
|
||||
|
||||
// [[codegen::verbatim(LabelsDistanceEPSInfo.description)]]
|
||||
std::optional<float> labelsDistanceEPS;
|
||||
|
||||
enum class Alignment {
|
||||
Horizontally,
|
||||
Circularly
|
||||
};
|
||||
// [[codegen::verbatim(LabelAlignmentOptionInfo.description)]]
|
||||
std::optional<Alignment> labelAlignmentOption;
|
||||
};
|
||||
#include "globelabelscomponent_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation GlobeLabelsComponent::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"GlobeLabels Component",
|
||||
"globebrowsing_globelabelscomponent",
|
||||
{
|
||||
{
|
||||
LabelsInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
LabelsInfo.description
|
||||
},
|
||||
{
|
||||
LabelsEnableInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
LabelsEnableInfo.description
|
||||
},
|
||||
{
|
||||
LabelsFontSizeInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LabelsFontSizeInfo.description
|
||||
},
|
||||
{
|
||||
LabelsMaxSizeInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LabelsMaxSizeInfo.description
|
||||
},
|
||||
{
|
||||
LabelsMinSizeInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LabelsMinSizeInfo.description
|
||||
},
|
||||
{
|
||||
LabelsSizeInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LabelsSizeInfo.description
|
||||
},
|
||||
{
|
||||
LabelsMinHeightInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LabelsMinHeightInfo.description
|
||||
},
|
||||
{
|
||||
LabelsColorInfo.identifier,
|
||||
new Color3Verifier,
|
||||
Optional::Yes,
|
||||
LabelsColorInfo.description
|
||||
},
|
||||
{
|
||||
LabelsOpacityInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LabelsOpacityInfo.description
|
||||
},
|
||||
{
|
||||
LabelsFadeInStartingDistanceInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LabelsFadeInStartingDistanceInfo.description
|
||||
},
|
||||
{
|
||||
LabelsFadeOutStartingDistanceInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LabelsFadeOutStartingDistanceInfo.description
|
||||
},
|
||||
{
|
||||
LabelsFadeInEnabledInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
LabelsFadeInEnabledInfo.description
|
||||
},
|
||||
{
|
||||
LabelsFadeOutEnabledInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
LabelsFadeOutEnabledInfo.description
|
||||
},
|
||||
{
|
||||
LabelsDisableCullingEnabledInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
LabelsDisableCullingEnabledInfo.description
|
||||
},
|
||||
{
|
||||
LabelsDistanceEPSInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LabelsDistanceEPSInfo.description
|
||||
},
|
||||
{
|
||||
LabelAlignmentOptionInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
LabelAlignmentOptionInfo.description
|
||||
},
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "globebrowsing_globelabelscomponent";
|
||||
return doc;
|
||||
}
|
||||
|
||||
GlobeLabelsComponent::GlobeLabelsComponent()
|
||||
@@ -293,7 +251,7 @@ GlobeLabelsComponent::GlobeLabelsComponent()
|
||||
, _labelsFadeInEnabled(LabelsFadeInEnabledInfo, false)
|
||||
, _labelsFadeOutEnabled(LabelsFadeOutEnabledInfo, false)
|
||||
, _labelsDisableCullingEnabled(LabelsDisableCullingEnabledInfo, false)
|
||||
, _labelsDistaneEPS(LabelsDistanceEPSInfo, 100000.f, 1000.f, 10000000.f)
|
||||
, _labelsDistanceEPS(LabelsDistanceEPSInfo, 100000.f, 1000.f, 10000000.f)
|
||||
, _labelAlignmentOption(
|
||||
LabelAlignmentOptionInfo,
|
||||
properties::OptionProperty::DisplayType::Dropdown
|
||||
@@ -312,7 +270,7 @@ GlobeLabelsComponent::GlobeLabelsComponent()
|
||||
addProperty(_labelsFadeInEnabled);
|
||||
addProperty(_labelsFadeOutEnabled);
|
||||
addProperty(_labelsDisableCullingEnabled);
|
||||
addProperty(_labelsDistaneEPS);
|
||||
addProperty(_labelsDistanceEPS);
|
||||
|
||||
_labelAlignmentOption.addOption(Horizontally, "Horizontally");
|
||||
_labelAlignmentOption.addOption(Circularly, "Circularly");
|
||||
@@ -324,125 +282,45 @@ void GlobeLabelsComponent::initialize(const ghoul::Dictionary& dictionary,
|
||||
globebrowsing::RenderableGlobe* globe)
|
||||
{
|
||||
ZoneScoped
|
||||
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"GlobeLabelsComponent"
|
||||
);
|
||||
|
||||
_globe = globe;
|
||||
|
||||
// Reads labels' file and build cache file if necessary
|
||||
if (dictionary.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!dictionary.hasValue<std::string>(KeyLabelsFileName)) {
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
if (!p.fileName.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string labelsFile = dictionary.value<std::string>(KeyLabelsFileName);
|
||||
bool loadSuccess = loadLabelsData(absPath(labelsFile));
|
||||
const bool loadSuccess = loadLabelsData(absPath(p.fileName->string()));
|
||||
if (!loadSuccess) {
|
||||
return;
|
||||
}
|
||||
if (dictionary.hasKey(LabelsEnableInfo.identifier)) {
|
||||
// In case of the label's dic is present but is disabled
|
||||
_labelsEnabled = dictionary.value<bool>(LabelsEnableInfo.identifier);
|
||||
}
|
||||
else {
|
||||
// Is the labels dic is enable in the configuration file,
|
||||
// enables the label automatically.
|
||||
_labelsEnabled = true;
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LabelsFontSizeInfo.identifier)) {
|
||||
_labelsFontSize = static_cast<float>(
|
||||
dictionary.value<double>(LabelsFontSizeInfo.identifier)
|
||||
);
|
||||
_labelsFontSize.onChange([this]() { initializeFonts(); });
|
||||
}
|
||||
_labelsEnabled = p.enable.value_or(true);
|
||||
_labelsFontSize = p.labelsFontSize.value_or(_labelsFontSize);
|
||||
_labelsFontSize.onChange([this]() { initializeFonts(); });
|
||||
_labelsSize = p.labelsSize.value_or(_labelsSize);
|
||||
_labelsMinHeight = p.labelsMinHeight.value_or(_labelsMinHeight);
|
||||
_labelsColor = p.labelsColor.value_or(_labelsColor);
|
||||
_labelsOpacity = p.labelsOpacity.value_or(_labelsOpacity);
|
||||
_labelsFadeInEnabled = p.labelsFadeInEnabled.value_or(_labelsFadeInEnabled);
|
||||
_labelsFadeInDist = p.fadeInStartingDistance.value_or(_labelsFadeInDist);
|
||||
_labelsFadeOutEnabled = p.labelsFadeOutEnabled.value_or(_labelsFadeOutEnabled);
|
||||
_labelsFadeOutDist = p.fadeOutStartingDistance.value_or(_labelsFadeOutDist);
|
||||
_labelsMinSize = p.labelsMinSize.value_or(_labelsMinSize);
|
||||
_labelsMaxSize = p.labelsMaxSize.value_or(_labelsMaxSize);
|
||||
_labelsDisableCullingEnabled =
|
||||
p.labelsDisableCullingEnabled.value_or(_labelsDisableCullingEnabled);
|
||||
_labelsDistanceEPS = p.labelsDistanceEPS.value_or(_labelsDistanceEPS);
|
||||
|
||||
if (dictionary.hasKey(LabelsSizeInfo.identifier)) {
|
||||
_labelsSize = static_cast<float>(
|
||||
dictionary.value<double>(LabelsSizeInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LabelsMinHeightInfo.identifier)) {
|
||||
_labelsMinHeight = static_cast<float>(
|
||||
dictionary.value<double>(LabelsMinHeightInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LabelsColorInfo.identifier)) {
|
||||
_labelsColor = dictionary.value<glm::dvec3>(LabelsColorInfo.identifier);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LabelsOpacityInfo.identifier)) {
|
||||
_labelsOpacity = static_cast<float>(
|
||||
dictionary.value<double>(LabelsOpacityInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LabelsFadeInEnabledInfo.identifier)) {
|
||||
_labelsFadeInEnabled = dictionary.value<bool>(LabelsFadeInEnabledInfo.identifier);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LabelsFadeInStartingDistanceInfo.identifier)) {
|
||||
_labelsFadeInDist = static_cast<float>(
|
||||
dictionary.value<double>(LabelsFadeInStartingDistanceInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LabelsFadeOutEnabledInfo.identifier)) {
|
||||
_labelsFadeOutEnabled = dictionary.value<bool>(
|
||||
LabelsFadeOutEnabledInfo.identifier
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LabelsFadeOutStartingDistanceInfo.identifier)) {
|
||||
_labelsFadeOutDist = static_cast<float>(
|
||||
dictionary.value<double>(LabelsFadeOutStartingDistanceInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LabelsMinSizeInfo.identifier)) {
|
||||
_labelsMinSize = static_cast<int>(
|
||||
dictionary.value<double>(LabelsMinSizeInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LabelsMaxSizeInfo.identifier)) {
|
||||
_labelsMaxSize = static_cast<int>(
|
||||
dictionary.value<double>(LabelsMaxSizeInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LabelsDisableCullingEnabledInfo.identifier)) {
|
||||
bool disabled = dictionary.value<bool>(
|
||||
LabelsDisableCullingEnabledInfo.identifier
|
||||
);
|
||||
_labelsDisableCullingEnabled = disabled;
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LabelsDistanceEPSInfo.identifier)) {
|
||||
_labelsDistaneEPS = static_cast<float>(
|
||||
dictionary.value<double>(LabelsDistanceEPSInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LabelAlignmentOptionInfo.identifier)) {
|
||||
std::string alignment =
|
||||
dictionary.value<std::string>(LabelAlignmentOptionInfo.identifier);
|
||||
if (alignment == "Horizontally") {
|
||||
_labelAlignmentOption = Horizontally;
|
||||
}
|
||||
else if (alignment == "Circularly" ) {
|
||||
_labelAlignmentOption = Circularly;
|
||||
}
|
||||
else {
|
||||
LERROR("Unknown alignment option: " + alignment);
|
||||
if (p.labelAlignmentOption.has_value()) {
|
||||
switch (*p.labelAlignmentOption) {
|
||||
case Parameters::Alignment::Horizontally:
|
||||
_labelAlignmentOption = Horizontally;
|
||||
break;
|
||||
case Parameters::Alignment::Circularly:
|
||||
_labelAlignmentOption = Circularly;
|
||||
break;
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,7 +610,7 @@ void GlobeLabelsComponent::renderLabels(const RenderData& data,
|
||||
glm::length(locationPositionWorld - data.camera.positionVec3());
|
||||
|
||||
if (_labelsDisableCullingEnabled ||
|
||||
((distToCamera > (distanceCameraToLabelWorld + _labelsDistaneEPS)) &&
|
||||
((distToCamera > (distanceCameraToLabelWorld + _labelsDistanceEPS)) &&
|
||||
isLabelInFrustum(VP, locationPositionWorld)))
|
||||
{
|
||||
if (_labelAlignmentOption == Circularly) {
|
||||
|
||||
@@ -96,7 +96,7 @@ private:
|
||||
properties::BoolProperty _labelsFadeInEnabled;
|
||||
properties::BoolProperty _labelsFadeOutEnabled;
|
||||
properties::BoolProperty _labelsDisableCullingEnabled;
|
||||
properties::FloatProperty _labelsDistaneEPS;
|
||||
properties::FloatProperty _labelsDistanceEPS;
|
||||
properties::OptionProperty _labelAlignmentOption;
|
||||
|
||||
private:
|
||||
|
||||
@@ -74,51 +74,33 @@ namespace {
|
||||
"as an offset from the heightmap. Otherwise, it will be an offset from the "
|
||||
"globe's reference ellipsoid. The default value is 'false'."
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(GlobeTranslation)]] Parameters {
|
||||
// [[codegen::verbatim(GlobeInfo.description)]]
|
||||
std::string globe
|
||||
[[codegen::annotation("A valid scene graph node with a RenderableGlobe")]];
|
||||
|
||||
// [[codegen::verbatim(LongitudeInfo.description)]]
|
||||
std::optional<double> longitude;
|
||||
|
||||
// [[codegen::verbatim(LatitudeInfo.description)]]
|
||||
std::optional<double> latitude;
|
||||
|
||||
// [[codegen::verbatim(AltitudeInfo.description)]]
|
||||
std::optional<double> altitude;
|
||||
|
||||
// [[codegen::verbatim(UseHeightmapInfo.description)]]
|
||||
std::optional<bool> useHeightmap;
|
||||
};
|
||||
#include "globetranslation_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
|
||||
documentation::Documentation GlobeTranslation::Documentation() {
|
||||
using namespace openspace::documentation;
|
||||
|
||||
return {
|
||||
"Globe Translation",
|
||||
"space_translation_globetranslation",
|
||||
{
|
||||
{
|
||||
GlobeInfo.identifier,
|
||||
new StringAnnotationVerifier(
|
||||
"A valid scene graph node with a RenderableGlobe"
|
||||
),
|
||||
Optional::No,
|
||||
GlobeInfo.description
|
||||
},
|
||||
{
|
||||
LongitudeInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LongitudeInfo.description
|
||||
},
|
||||
{
|
||||
LatitudeInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LatitudeInfo.description,
|
||||
},
|
||||
{
|
||||
AltitudeInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
AltitudeInfo.description
|
||||
},
|
||||
{
|
||||
UseHeightmapInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
UseHeightmapInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "space_translation_globetranslation";
|
||||
return doc;
|
||||
}
|
||||
|
||||
GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary)
|
||||
@@ -128,39 +110,28 @@ GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary)
|
||||
, _altitude(AltitudeInfo, 0.0, 0.0, 1e12)
|
||||
, _useHeightmap(UseHeightmapInfo, false)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"GlobeTranslation"
|
||||
);
|
||||
|
||||
_globe = dictionary.value<std::string>(GlobeInfo.identifier);
|
||||
if (dictionary.hasKey(LongitudeInfo.identifier)) {
|
||||
_longitude = dictionary.value<double>(LongitudeInfo.identifier);
|
||||
}
|
||||
if (dictionary.hasKey(LatitudeInfo.identifier)) {
|
||||
_latitude = dictionary.value<double>(LatitudeInfo.identifier);
|
||||
}
|
||||
if (dictionary.hasKey(AltitudeInfo.identifier)) {
|
||||
_altitude = dictionary.value<double>(AltitudeInfo.identifier);
|
||||
}
|
||||
if (dictionary.hasKey(UseHeightmapInfo.identifier)) {
|
||||
_useHeightmap = dictionary.value<bool>(UseHeightmapInfo.identifier);
|
||||
}
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_globe = p.globe;
|
||||
_globe.onChange([this]() {
|
||||
fillAttachedNode();
|
||||
_positionIsDirty = true;
|
||||
});
|
||||
|
||||
_longitude = p.longitude.value_or(_longitude);
|
||||
_longitude.onChange([this]() { _positionIsDirty = true; });
|
||||
_latitude.onChange([this]() { _positionIsDirty = true; });
|
||||
_altitude.onChange([this]() { _positionIsDirty = true; });
|
||||
_useHeightmap.onChange([this]() { _positionIsDirty = true; });
|
||||
|
||||
addProperty(_longitude);
|
||||
|
||||
_latitude = p.latitude.value_or(_latitude);
|
||||
_latitude.onChange([this]() { _positionIsDirty = true; });
|
||||
addProperty(_latitude);
|
||||
|
||||
_altitude = p.altitude.value_or(_altitude);
|
||||
_altitude.onChange([this]() { _positionIsDirty = true; });
|
||||
addProperty(_altitude);
|
||||
|
||||
_useHeightmap = p.useHeightmap.value_or(_useHeightmap);
|
||||
_useHeightmap.onChange([this]() { _positionIsDirty = true; });
|
||||
addProperty(_useHeightmap);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,9 @@
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <optional>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyType = "Type";
|
||||
constexpr const char* KeyChromaKeyColor = "ChromaKeyColor";
|
||||
constexpr const char* KeyChromaKeyTolerance = "ChromaKeyTolerance";
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ChromaKeyColorInfo = {
|
||||
"ChromaKeyColor",
|
||||
"Chroma Key Color",
|
||||
@@ -50,37 +47,32 @@ namespace {
|
||||
"Type",
|
||||
"The type of layer adjustment that is applied to the underlying layer."
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(LayerAdjustment)]] Parameters {
|
||||
enum class Type {
|
||||
None,
|
||||
ChromaKey,
|
||||
TransferFunction
|
||||
};
|
||||
// Specifies the type of the adjustment that is applied
|
||||
std::optional<Type> type;
|
||||
|
||||
// Specifies the chroma key used when selecting 'ChromaKey' for the 'Type'
|
||||
std::optional<glm::vec3> chromaKeyColor [[codegen::color()]];
|
||||
|
||||
// Specifies the tolerance to match the color to the chroma key when the
|
||||
// 'ChromaKey' type is selected for the 'Type'
|
||||
std::optional<float> chromaKeyTolerance;
|
||||
};
|
||||
#include "layeradjustment_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
|
||||
documentation::Documentation LayerAdjustment::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"LayerAdjustment",
|
||||
"globebrowsing_layeradjustment",
|
||||
{
|
||||
{
|
||||
KeyType,
|
||||
new StringInListVerifier({ "None", "ChromaKey", "TransferFunction" }),
|
||||
Optional::Yes,
|
||||
"Specifies the type of the adjustment that is applied"
|
||||
},
|
||||
{
|
||||
KeyChromaKeyColor,
|
||||
new Color3Verifier,
|
||||
Optional::Yes,
|
||||
"Specifies the chroma key used when selecting 'ChromaKey' for the 'Type'."
|
||||
},
|
||||
{
|
||||
KeyChromaKeyTolerance,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies the tolerance to match the color to the chroma key when the "
|
||||
"'ChromaKey' type is selected for the 'Type'."
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "globebrowsing_layeradjustment";
|
||||
return doc;
|
||||
}
|
||||
|
||||
LayerAdjustment::LayerAdjustment()
|
||||
@@ -121,31 +113,27 @@ LayerAdjustment::LayerAdjustment()
|
||||
}
|
||||
|
||||
void LayerAdjustment::setValuesFromDictionary(const ghoul::Dictionary& adjustmentDict) {
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
adjustmentDict,
|
||||
"LayerAdjustment"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(adjustmentDict);
|
||||
|
||||
if (adjustmentDict.hasValue<std::string>(KeyType)) {
|
||||
std::string dictType = adjustmentDict.value<std::string>(KeyType);
|
||||
_typeOption = static_cast<int>(
|
||||
ghoul::from_string<layergroupid::AdjustmentTypeID>(dictType)
|
||||
);
|
||||
if (p.type.has_value()) {
|
||||
switch (*p.type) {
|
||||
case Parameters::Type::None:
|
||||
_typeOption = static_cast<int>(layergroupid::AdjustmentTypeID::None);
|
||||
break;
|
||||
case Parameters::Type::ChromaKey:
|
||||
_typeOption = static_cast<int>(layergroupid::AdjustmentTypeID::ChromaKey);
|
||||
break;
|
||||
case Parameters::Type::TransferFunction:
|
||||
_typeOption =
|
||||
static_cast<int>(layergroupid::AdjustmentTypeID::TransferFunction);
|
||||
break;
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}
|
||||
|
||||
if (adjustmentDict.hasValue<glm::dvec3>(KeyChromaKeyColor)) {
|
||||
glm::vec3 dictChromaKeyColor =
|
||||
adjustmentDict.value<glm::dvec3>(KeyChromaKeyColor);
|
||||
_chromaKeyColor = std::move(dictChromaKeyColor);
|
||||
}
|
||||
|
||||
if (adjustmentDict.hasValue<double>(KeyChromaKeyTolerance)) {
|
||||
float dictChromaKeyTolerance = static_cast<float>(
|
||||
adjustmentDict.value<double>(KeyChromaKeyTolerance)
|
||||
);
|
||||
_chromaKeyTolerance = dictChromaKeyTolerance;
|
||||
}
|
||||
_chromaKeyColor = p.chromaKeyColor.value_or(_chromaKeyColor);
|
||||
_chromaKeyTolerance = p.chromaKeyTolerance.value_or(_chromaKeyTolerance);
|
||||
}
|
||||
|
||||
layergroupid::AdjustmentTypeID LayerAdjustment::type() const {
|
||||
|
||||
@@ -949,7 +949,8 @@ TileMetaData RawTileDataReader::tileMetaData(RawTile& rawTile,
|
||||
|
||||
bool allIsMissing = true;
|
||||
for (int y = 0; y < region.numPixels.y; ++y) {
|
||||
const size_t yi = (static_cast<unsigned long long>(region.numPixels.y) - 1 - y) * bytesPerLine;
|
||||
const size_t yi =
|
||||
(static_cast<unsigned long long>(region.numPixels.y) - 1 - y) * bytesPerLine;
|
||||
size_t i = 0;
|
||||
for (int x = 0; x < region.numPixels.x; ++x) {
|
||||
for (size_t raster = 0; raster < _initData.nRasters; ++raster) {
|
||||
|
||||
@@ -79,11 +79,6 @@ namespace {
|
||||
bool isShadowing = false;
|
||||
};
|
||||
|
||||
constexpr const char* KeyRadii = "Radii";
|
||||
constexpr const char* KeyLayers = "Layers";
|
||||
constexpr const char* KeyShadowGroup = "ShadowGroup";
|
||||
constexpr const char* KeyLabels = "Labels";
|
||||
|
||||
const openspace::globebrowsing::AABB3 CullingFrustum{
|
||||
glm::vec3(-1.f, -1.f, 0.f),
|
||||
glm::vec3( 1.f, 1.f, 1e35)
|
||||
@@ -232,6 +227,47 @@ namespace {
|
||||
"This is the number of currently active layers, if this value reaches the "
|
||||
"maximum, bad things will happen."
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(RenderableGlobe)]] Parameters {
|
||||
// Specifies the radii for this planet. If the Double version of this is used, all
|
||||
// three radii are assumed to be equal
|
||||
std::optional<std::variant<glm::dvec3, double>> radii;
|
||||
|
||||
// Specifies whether the planet should be shaded by the primary light source or
|
||||
// not. If it is disabled, all parts of the planet are illuminated
|
||||
std::optional<bool> performShading;
|
||||
|
||||
// A list of all the layers that should be added
|
||||
std::map<std::string, ghoul::Dictionary> layers
|
||||
[[codegen::reference("globebrowsing_layermanager")]];
|
||||
|
||||
// Specifies information about planetary labels that can be rendered on the
|
||||
// object's surface
|
||||
std::optional<ghoul::Dictionary> labels
|
||||
[[codegen::reference("globebrowsing_globelabelscomponent")]];
|
||||
|
||||
struct ShadowGroup {
|
||||
struct Source {
|
||||
std::string name;
|
||||
double radius;
|
||||
};
|
||||
std::vector<Source> sources;
|
||||
|
||||
struct Caster {
|
||||
std::string name;
|
||||
double radius;
|
||||
};
|
||||
std::vector<Caster> casters;
|
||||
};
|
||||
std::optional<ShadowGroup> shadowGroup;
|
||||
|
||||
std::optional<ghoul::Dictionary> rings
|
||||
[[codegen::reference("globebrowsing_rings_component")]];
|
||||
|
||||
std::optional<ghoul::Dictionary> shadows
|
||||
[[codegen::reference("globebrowsing_shadows_component")]];
|
||||
};
|
||||
#include "renderableglobe_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
using namespace openspace::properties;
|
||||
@@ -461,48 +497,9 @@ Chunk::Chunk(const TileIndex& ti)
|
||||
{}
|
||||
|
||||
documentation::Documentation RenderableGlobe::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"RenderableGlobe",
|
||||
"globebrowsing_renderableglobe",
|
||||
{
|
||||
{
|
||||
KeyRadii,
|
||||
new OrVerifier({ new DoubleVector3Verifier, new DoubleVerifier }),
|
||||
Optional::Yes,
|
||||
"Specifies the radii for this planet. If the Double version of this is "
|
||||
"used, all three radii are assumed to be equal."
|
||||
},
|
||||
{
|
||||
"PerformShading",
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies whether the planet should be shaded by the primary light "
|
||||
"source or not. If it is disabled, all parts of the planet are "
|
||||
"illuminated."
|
||||
},
|
||||
{
|
||||
KeyLayers,
|
||||
new TableVerifier({
|
||||
{
|
||||
"*",
|
||||
new ReferencingVerifier("globebrowsing_layermanager"),
|
||||
Optional::Yes,
|
||||
"Descriptions of the individual layer groups"
|
||||
}
|
||||
}),
|
||||
Optional::Yes,
|
||||
"A list of all the layers that should be added"
|
||||
},
|
||||
{
|
||||
KeyLabels,
|
||||
new ReferencingVerifier("globebrowsing_globelabelscomponent"),
|
||||
Optional::Yes,
|
||||
"Specifies information about planetary labels that can be rendered on "
|
||||
"the object's surface."
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "globebrowsing_renderableglobe";
|
||||
return doc;
|
||||
}
|
||||
|
||||
RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
|
||||
@@ -539,75 +536,52 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
|
||||
, _ringsComponent(dictionary)
|
||||
, _shadowComponent(dictionary)
|
||||
{
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_generalProperties.currentLodScaleFactor.setReadOnly(true);
|
||||
|
||||
// Read the radii in to its own dictionary
|
||||
if (dictionary.hasValue<glm::dvec3>(KeyRadii)) {
|
||||
_ellipsoid = Ellipsoid(dictionary.value<glm::dvec3>(KeyRadii));
|
||||
setBoundingSphere(static_cast<float>(_ellipsoid.maximumRadius()));
|
||||
}
|
||||
else if (dictionary.hasValue<double>(KeyRadii)) {
|
||||
const double radius = dictionary.value<double>(KeyRadii);
|
||||
_ellipsoid = Ellipsoid({ radius, radius, radius });
|
||||
setBoundingSphere(static_cast<float>(_ellipsoid.maximumRadius()));
|
||||
if (p.radii.has_value()) {
|
||||
if (std::holds_alternative<glm::dvec3>(*p.radii)) {
|
||||
_ellipsoid = Ellipsoid(std::get<glm::dvec3>(*p.radii));
|
||||
setBoundingSphere(static_cast<float>(_ellipsoid.maximumRadius()));
|
||||
}
|
||||
else if (std::holds_alternative<double>(*p.radii)) {
|
||||
const double radius = std::get<double>(*p.radii);
|
||||
_ellipsoid = Ellipsoid({ radius, radius, radius });
|
||||
setBoundingSphere(static_cast<float>(_ellipsoid.maximumRadius()));
|
||||
}
|
||||
else {
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionary.hasKey("PerformShading")) {
|
||||
_generalProperties.performShading = dictionary.value<bool>("PerformShading");
|
||||
}
|
||||
_generalProperties.performShading =
|
||||
p.performShading.value_or(_generalProperties.performShading);
|
||||
|
||||
|
||||
// Init layer manager
|
||||
ghoul::Dictionary layersDictionary;
|
||||
if (!dictionary.hasValue<ghoul::Dictionary>(KeyLayers)) {
|
||||
throw ghoul::RuntimeError(std::string(KeyLayers) + " must be specified");
|
||||
}
|
||||
layersDictionary = dictionary.value<ghoul::Dictionary>(KeyLayers);
|
||||
|
||||
// @TODO (abock, 2021-03-25) The layermanager should be changed to take a
|
||||
// std::map<std::string, ghoul::Dictionary> instead and then we don't need to get it
|
||||
// as a bare dictionary anymore and can use the value from the struct directly
|
||||
ghoul::Dictionary layersDictionary = dictionary.value<ghoul::Dictionary>("Layers");
|
||||
_layerManager.initialize(layersDictionary);
|
||||
|
||||
addProperty(_generalProperties.performShading);
|
||||
addProperty(_generalProperties.useAccurateNormals);
|
||||
|
||||
// ================================================================
|
||||
// ======== Reads Shadow (Eclipses) Entries in asset file =========
|
||||
// ================================================================
|
||||
if (dictionary.hasValue<ghoul::Dictionary>(KeyShadowGroup)) {
|
||||
ghoul::Dictionary shadowDictionary =
|
||||
dictionary.value<ghoul::Dictionary>(KeyShadowGroup);
|
||||
|
||||
std::vector<std::pair<std::string, double>> sourceArray;
|
||||
ghoul::Dictionary sources = shadowDictionary.value<ghoul::Dictionary>("Sources");
|
||||
for (std::string_view k : sources.keys()) {
|
||||
ghoul::Dictionary source = sources.value<ghoul::Dictionary>(k);
|
||||
|
||||
std::string name = source.value<std::string>("Name");
|
||||
double radius = source.value<double>("Radius");
|
||||
sourceArray.emplace_back(name, radius);
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, double>> casterArray;
|
||||
ghoul::Dictionary casters = shadowDictionary.value<ghoul::Dictionary>("Casters");
|
||||
for (std::string_view k : casters.keys()) {
|
||||
ghoul::Dictionary caster = casters.value<ghoul::Dictionary>(k);
|
||||
|
||||
std::string name = caster.value<std::string>("Name");
|
||||
double radius = caster.value<double>("Radius");
|
||||
casterArray.emplace_back(name, radius);
|
||||
}
|
||||
|
||||
if (p.shadowGroup.has_value()) {
|
||||
std::vector<Ellipsoid::ShadowConfiguration> shadowConfArray;
|
||||
for (const std::pair<std::string, double>& source : sourceArray) {
|
||||
for (const std::pair<std::string, double>& caster : casterArray) {
|
||||
for (const Parameters::ShadowGroup::Source& source : p.shadowGroup->sources) {
|
||||
for (const Parameters::ShadowGroup::Caster& caster : p.shadowGroup->casters) {
|
||||
Ellipsoid::ShadowConfiguration sc;
|
||||
sc.source = source;
|
||||
sc.caster = caster;
|
||||
sc.source = std::pair<std::string, double>(source.name, source.radius);
|
||||
sc.caster = std::pair<std::string, double>(source.name, source.radius);
|
||||
shadowConfArray.push_back(sc);
|
||||
}
|
||||
}
|
||||
_ellipsoid.setShadowConfigurationArray(shadowConfArray);
|
||||
}
|
||||
|
||||
if (!_ellipsoid.shadowConfigurationArray().empty()) {
|
||||
addProperty(_generalProperties.eclipseShadowsEnabled);
|
||||
addProperty(_generalProperties.eclipseHardShadows);
|
||||
}
|
||||
@@ -667,22 +641,20 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
|
||||
_localChunkBuffer.resize(2048);
|
||||
_traversalMemory.resize(512);
|
||||
|
||||
// Labels Dictionary
|
||||
if (dictionary.hasValue<ghoul::Dictionary>(KeyLabels)) {
|
||||
_labelsDictionary = dictionary.value<ghoul::Dictionary>(KeyLabels);
|
||||
}
|
||||
_labelsDictionary = p.labels.value_or(_labelsDictionary);
|
||||
|
||||
|
||||
// Components
|
||||
if (dictionary.hasValue<ghoul::Dictionary>("Rings")) {
|
||||
_hasRings = p.rings.has_value();
|
||||
if (_hasRings) {
|
||||
_ringsComponent.initialize();
|
||||
addPropertySubOwner(_ringsComponent);
|
||||
_hasRings = true;
|
||||
}
|
||||
|
||||
if (dictionary.hasKey("Shadows")) {
|
||||
_hasShadows = p.shadows.has_value();
|
||||
if (_hasShadows) {
|
||||
_shadowComponent.initialize();
|
||||
addPropertySubOwner(_shadowComponent);
|
||||
_hasShadows = true;
|
||||
_generalProperties.shadowMapping = true;
|
||||
}
|
||||
_generalProperties.shadowMapping.onChange(notifyShaderRecompilation);
|
||||
@@ -1487,7 +1459,7 @@ void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& d
|
||||
|
||||
program.setUniform("shadowMapTexture", shadowMapUnit);
|
||||
program.setUniform("zFightingPercentage", _generalProperties.zFightingPercentage);
|
||||
}
|
||||
}
|
||||
else if (_generalProperties.shadowMapping) {
|
||||
shadowMapUnit.activate();
|
||||
// JCC: Avoiding a to recompiling the shaders or having more than one
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/opengl/textureunit.h>
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
#include <locale>
|
||||
@@ -155,90 +156,53 @@ namespace {
|
||||
"The number of samples used during shadow mapping calculation "
|
||||
"(Percentage Closer Filtering)."
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(RingsComponent)]] Parameters {
|
||||
// [[codegen::verbatim(TextureInfo.description)]]
|
||||
std::optional<std::filesystem::path> texture;
|
||||
|
||||
// [[codegen::verbatim(TextureFwrdInfo.description)]]
|
||||
std::optional<std::filesystem::path> textureFwrd;
|
||||
|
||||
// [[codegen::verbatim(TextureBckwrdInfo.description)]]
|
||||
std::optional<std::filesystem::path> textureBckwrd;
|
||||
|
||||
// [[codegen::verbatim(TextureUnlitInfo.description)]]
|
||||
std::optional<std::filesystem::path> textureUnlit;
|
||||
|
||||
// [[codegen::verbatim(TextureColorInfo.description)]]
|
||||
std::optional<std::filesystem::path> textureColor;
|
||||
|
||||
// [[codegen::verbatim(TextureTransparencyInfo.description)]]
|
||||
std::optional<std::filesystem::path> textureTransparency;
|
||||
|
||||
// [[codegen::verbatim(SizeInfo.description)]]
|
||||
std::optional<float> size;
|
||||
|
||||
// [[codegen::verbatim(OffsetInfo.description)]]
|
||||
std::optional<glm::vec2> offset;
|
||||
|
||||
// [[codegen::verbatim(NightFactorInfo.description)]]
|
||||
std::optional<float> nightFactor;
|
||||
|
||||
// [[codegen::verbatim(ColorFilterInfo.description)]]
|
||||
std::optional<float> colorFilter;
|
||||
|
||||
// [[codegen::verbatim(ZFightingPercentageInfo.description)]]
|
||||
std::optional<float> zFightingPercentage;
|
||||
|
||||
// [[codegen::verbatim(NumberShadowSamplesInfo.description)]]
|
||||
std::optional<int> numberShadowSamples;
|
||||
};
|
||||
#include "ringscomponent_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation RingsComponent::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"Rings Component",
|
||||
"globebrowsing_rings_component",
|
||||
{
|
||||
{
|
||||
TextureInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
TextureInfo.description
|
||||
},
|
||||
{
|
||||
TextureFwrdInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
TextureFwrdInfo.description
|
||||
},
|
||||
{
|
||||
TextureBckwrdInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
TextureBckwrdInfo.description
|
||||
},
|
||||
{
|
||||
TextureUnlitInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
TextureUnlitInfo.description
|
||||
},
|
||||
{
|
||||
TextureColorInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
TextureColorInfo.description
|
||||
},
|
||||
{
|
||||
TextureTransparencyInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
TextureTransparencyInfo.description
|
||||
},
|
||||
{
|
||||
SizeInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
SizeInfo.description
|
||||
},
|
||||
{
|
||||
OffsetInfo.identifier,
|
||||
new DoubleVector2Verifier,
|
||||
Optional::Yes,
|
||||
OffsetInfo.description
|
||||
},
|
||||
{
|
||||
NightFactorInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
NightFactorInfo.description
|
||||
},
|
||||
{
|
||||
ColorFilterInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
ColorFilterInfo.description
|
||||
},
|
||||
{
|
||||
ZFightingPercentageInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
ZFightingPercentageInfo.description
|
||||
},
|
||||
{
|
||||
NumberShadowSamplesInfo.identifier,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
NumberShadowSamplesInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "globebrowsing_rings_component";
|
||||
return doc;
|
||||
}
|
||||
|
||||
RingsComponent::RingsComponent(const ghoul::Dictionary& dictionary)
|
||||
@@ -265,14 +229,17 @@ RingsComponent::RingsComponent(const ghoul::Dictionary& dictionary)
|
||||
// term and rather extract the values directly here. This would require a bit of
|
||||
// a rewrite in the RenderableGlobe class to not create the RingsComponent in the
|
||||
// class-initializer list though
|
||||
// @TODO (abock, 2021-03-25) Righto! The RenderableGlobe passes this dictionary
|
||||
// in as-is so it would be easy to just pass it directly to the initialize method
|
||||
// instead
|
||||
_ringsDictionary = dictionary.value<ghoul::Dictionary>("Rings");
|
||||
}
|
||||
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
_ringsDictionary,
|
||||
"RingsComponent"
|
||||
);
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
_ringsDictionary,
|
||||
"RingsComponent"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void RingsComponent::initialize() {
|
||||
@@ -280,106 +247,78 @@ void RingsComponent::initialize() {
|
||||
|
||||
using ghoul::filesystem::File;
|
||||
|
||||
const Parameters p = codegen::bake<Parameters>(_ringsDictionary);
|
||||
|
||||
addProperty(_enabled);
|
||||
|
||||
_size = static_cast<float>(_ringsDictionary.value<double>(SizeInfo.identifier));
|
||||
//setBoundingSphere(_size);
|
||||
_size = p.size.value_or(_size);
|
||||
_size.onChange([&]() { _planeIsDirty = true; });
|
||||
addProperty(_size);
|
||||
|
||||
if (_ringsDictionary.hasKey(TextureInfo.identifier)) {
|
||||
_texturePath = absPath(
|
||||
_ringsDictionary.value<std::string>(TextureInfo.identifier)
|
||||
);
|
||||
if (p.texture.has_value()) {
|
||||
_texturePath = absPath(p.texture->string());
|
||||
_textureFile = std::make_unique<File>(_texturePath);
|
||||
_texturePath.onChange([&]() { loadTexture(); });
|
||||
addProperty(_texturePath);
|
||||
_textureFile->setCallback([&](const File&) { _textureIsDirty = true; });
|
||||
}
|
||||
|
||||
if (_ringsDictionary.hasKey(TextureFwrdInfo.identifier)) {
|
||||
_textureFwrdPath = absPath(
|
||||
_ringsDictionary.value<std::string>(TextureFwrdInfo.identifier)
|
||||
);
|
||||
if (p.textureFwrd.has_value()) {
|
||||
_textureFwrdPath = absPath(p.textureFwrd->string());
|
||||
_textureFileForwards = std::make_unique<File>(_textureFwrdPath);
|
||||
_textureFwrdPath.onChange([&]() { loadTexture(); });
|
||||
addProperty(_textureFwrdPath);
|
||||
_textureFileForwards->setCallback([&](const File&) { _textureIsDirty = true; });
|
||||
}
|
||||
|
||||
if (_ringsDictionary.hasKey(TextureBckwrdInfo.identifier)) {
|
||||
_textureBckwrdPath = absPath(
|
||||
_ringsDictionary.value<std::string>(TextureBckwrdInfo.identifier)
|
||||
);
|
||||
|
||||
if (p.textureBckwrd.has_value()) {
|
||||
_textureBckwrdPath = absPath(p.textureBckwrd->string());
|
||||
_textureFileBackwards = std::make_unique<File>(_textureBckwrdPath);
|
||||
_textureBckwrdPath.onChange([&]() { loadTexture(); });
|
||||
addProperty(_textureBckwrdPath);
|
||||
_textureFileBackwards->setCallback([&](const File&) { _textureIsDirty = true; });
|
||||
}
|
||||
|
||||
if (_ringsDictionary.hasKey(TextureUnlitInfo.identifier)) {
|
||||
_textureUnlitPath = absPath(
|
||||
_ringsDictionary.value<std::string>(TextureUnlitInfo.identifier)
|
||||
);
|
||||
if (p.textureUnlit.has_value()) {
|
||||
_textureUnlitPath = absPath(p.textureUnlit->string());
|
||||
_textureFileUnlit = std::make_unique<File>(_textureUnlitPath);
|
||||
_textureUnlitPath.onChange([&]() { loadTexture(); });
|
||||
addProperty(_textureUnlitPath);
|
||||
_textureFileUnlit->setCallback([&](const File&) { _textureIsDirty = true; });
|
||||
}
|
||||
|
||||
if (_ringsDictionary.hasKey(TextureColorInfo.identifier)) {
|
||||
_textureColorPath = absPath(
|
||||
_ringsDictionary.value<std::string>(TextureColorInfo.identifier)
|
||||
);
|
||||
if (p.textureColor.has_value()) {
|
||||
_textureColorPath = absPath(p.textureColor->string());
|
||||
_textureFileColor = std::make_unique<File>(_textureColorPath);
|
||||
_textureColorPath.onChange([&]() { loadTexture(); });
|
||||
addProperty(_textureColorPath);
|
||||
_textureFileColor->setCallback([&](const File&) { _textureIsDirty = true; });
|
||||
}
|
||||
|
||||
if (_ringsDictionary.hasKey(TextureTransparencyInfo.identifier)) {
|
||||
_textureTransparencyPath = absPath(
|
||||
_ringsDictionary.value<std::string>(TextureTransparencyInfo.identifier)
|
||||
);
|
||||
if (p.textureTransparency.has_value()) {
|
||||
_textureTransparencyPath = absPath(p.textureTransparency->string());
|
||||
_textureFileTransparency = std::make_unique<File>(_textureTransparencyPath);
|
||||
_textureTransparencyPath.onChange([&]() { loadTexture(); });
|
||||
addProperty(_textureTransparencyPath);
|
||||
_textureFileTransparency->setCallback([&](const File&) { _textureIsDirty = true; });
|
||||
}
|
||||
|
||||
if (_ringsDictionary.hasValue<glm::dvec2>(OffsetInfo.identifier)) {
|
||||
_offset = _ringsDictionary.value<glm::dvec2>(OffsetInfo.identifier);
|
||||
}
|
||||
_offset = p.offset.value_or(_offset);
|
||||
addProperty(_offset);
|
||||
|
||||
if (_ringsDictionary.hasValue<double>(NightFactorInfo.identifier)) {
|
||||
_nightFactor = static_cast<float>(
|
||||
_ringsDictionary.value<double>(NightFactorInfo.identifier)
|
||||
);
|
||||
}
|
||||
_nightFactor = p.nightFactor.value_or(_nightFactor);
|
||||
addProperty(_nightFactor);
|
||||
|
||||
if (_ringsDictionary.hasValue<double>(ColorFilterInfo.identifier)) {
|
||||
_colorFilter = static_cast<float>(
|
||||
_ringsDictionary.value<double>(ColorFilterInfo.identifier)
|
||||
);
|
||||
}
|
||||
_colorFilter = p.colorFilter.value_or(_colorFilter);
|
||||
addProperty(_colorFilter);
|
||||
|
||||
// Shadow Mapping Quality Controls
|
||||
if (_ringsDictionary.hasKey(ZFightingPercentageInfo.identifier)) {
|
||||
_zFightingPercentage = static_cast<float>(
|
||||
_ringsDictionary.value<double>(ZFightingPercentageInfo.identifier)
|
||||
);
|
||||
}
|
||||
_zFightingPercentage = p.zFightingPercentage.value_or(_zFightingPercentage);
|
||||
addProperty(_zFightingPercentage);
|
||||
|
||||
if (_ringsDictionary.hasKey(NumberShadowSamplesInfo.identifier)) {
|
||||
_nShadowSamples = _ringsDictionary.value<int>(NumberShadowSamplesInfo.identifier);
|
||||
}
|
||||
_nShadowSamples = p.numberShadowSamples.value_or(_nShadowSamples);
|
||||
_nShadowSamples.onChange([this]() { compileShadowShader(); });
|
||||
addProperty(_nShadowSamples);
|
||||
|
||||
addProperty(_colorFilter);
|
||||
}
|
||||
|
||||
bool RingsComponent::isReady() const {
|
||||
@@ -476,7 +415,7 @@ void RingsComponent::draw(const RenderData& data,
|
||||
_shader->setUniform(_uniformCacheAdvancedRings.colorFilterValue, _colorFilter);
|
||||
_shader->setUniform(_uniformCacheAdvancedRings.nightFactor, _nightFactor);
|
||||
_shader->setUniform(_uniformCacheAdvancedRings.sunPosition, _sunPosition);
|
||||
|
||||
|
||||
const glm::dmat4 inverseModelTransform = glm::inverse(modelTransform);
|
||||
|
||||
glm::vec3 sunPositionObjectSpace = glm::normalize(
|
||||
@@ -614,7 +553,7 @@ void RingsComponent::draw(const RenderData& data,
|
||||
else {
|
||||
_texture->bind();
|
||||
}
|
||||
|
||||
|
||||
_geometryOnlyShader->setUniform(_geomUniformCache.ringTexture, ringTextureUnit);
|
||||
}
|
||||
|
||||
@@ -673,7 +612,7 @@ void RingsComponent::loadTexture() {
|
||||
using namespace ghoul::opengl;
|
||||
|
||||
if (!_texturePath.value().empty()) {
|
||||
|
||||
|
||||
std::unique_ptr<Texture> texture = TextureReader::ref().loadTexture(
|
||||
absPath(_texturePath)
|
||||
);
|
||||
|
||||
@@ -98,7 +98,7 @@ private:
|
||||
) _uniformCache;
|
||||
UniformCache(modelViewProjectionMatrix, textureOffset, colorFilterValue, nightFactor,
|
||||
sunPosition, sunPositionObj, camPositionObj, ringTextureFwrd, ringTextureBckwrd,
|
||||
ringTextureUnlit, ringTextureColor, ringTextureTransparency, shadowMatrix,
|
||||
ringTextureUnlit, ringTextureColor, ringTextureTransparency, shadowMatrix,
|
||||
shadowMapTexture, zFightingPercentage
|
||||
) _uniformCacheAdvancedRings;
|
||||
UniformCache(modelViewProjectionMatrix, textureOffset, ringTexture
|
||||
|
||||
@@ -141,30 +141,23 @@ namespace {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct [[codegen::Dictionary(ShadowComponent)]] Parameters {
|
||||
// [[codegen::verbatim(DistanceFractionInfo.description)]]
|
||||
std::optional<int> distanceFraction;
|
||||
|
||||
// [[codegen::verbatim(DepthMapSizeInfo.description)]]
|
||||
std::optional<glm::ivec2> depthMapSize;
|
||||
};
|
||||
#include "shadowcomponent_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation ShadowComponent::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"ShadowsRing Component",
|
||||
"globebrowsing_shadows_component",
|
||||
{
|
||||
{
|
||||
DistanceFractionInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
DistanceFractionInfo.description
|
||||
},
|
||||
{
|
||||
DepthMapSizeInfo.identifier,
|
||||
new Vector2ListVerifier<double>,
|
||||
Optional::Yes,
|
||||
DepthMapSizeInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "globebrowsing_shadows_component";
|
||||
return doc;
|
||||
}
|
||||
|
||||
ShadowComponent::ShadowComponent(const ghoul::Dictionary& dictionary)
|
||||
@@ -172,37 +165,30 @@ ShadowComponent::ShadowComponent(const ghoul::Dictionary& dictionary)
|
||||
, _saveDepthTexture(SaveDepthTextureInfo)
|
||||
, _distanceFraction(DistanceFractionInfo, 20, 1, 10000)
|
||||
, _enabled({ "Enabled", "Enabled", "Enable/Disable Shadows" }, true)
|
||||
, _shadowMapDictionary(dictionary)
|
||||
{
|
||||
using ghoul::filesystem::File;
|
||||
|
||||
if (dictionary.hasValue<ghoul::Dictionary>("Shadows")) {
|
||||
// @TODO (abock, 2019-12-16) It would be better to not store the dictionary long
|
||||
// term and rather extract the values directly here. This would require a bit of
|
||||
// a rewrite in the RenderableGlobe class to not create the ShadowComponent in the
|
||||
// class-initializer list though
|
||||
_shadowMapDictionary = dictionary.value<ghoul::Dictionary>("Shadows");
|
||||
// @TODO (abock, 2021-03-25) This is not really a nice solution as this key name is
|
||||
// coded into the RenderableGlobe. Instead, the parent should unpack the dictionary
|
||||
// and pass the unpacked dictionary in here; Or maybe we don't want a dictionary at
|
||||
// this state anyway?
|
||||
if (!dictionary.hasValue<ghoul::Dictionary>("Shadows")) {
|
||||
return;
|
||||
}
|
||||
ghoul::Dictionary d = dictionary.value<ghoul::Dictionary>("Shadows");
|
||||
|
||||
const Parameters p = codegen::bake<Parameters>(d);
|
||||
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
_shadowMapDictionary,
|
||||
"ShadowComponent"
|
||||
);
|
||||
addProperty(_enabled);
|
||||
|
||||
_distanceFraction = p.distanceFraction.value_or(_distanceFraction);
|
||||
addProperty(_distanceFraction);
|
||||
|
||||
if (_shadowMapDictionary.hasKey(DistanceFractionInfo.identifier)) {
|
||||
_distanceFraction = static_cast<int>(
|
||||
_shadowMapDictionary.value<double>(DistanceFractionInfo.identifier)
|
||||
);
|
||||
}
|
||||
_saveDepthTexture.onChange([&]() { _executeDepthTextureSave = true; });
|
||||
|
||||
|
||||
if (_shadowMapDictionary.hasKey(DepthMapSizeInfo.identifier)) {
|
||||
glm::dvec2 depthMapSize =
|
||||
_shadowMapDictionary.value<glm::dvec2>(DepthMapSizeInfo.identifier);
|
||||
_shadowDepthTextureWidth = static_cast<int>(depthMapSize.x);
|
||||
_shadowDepthTextureHeight = static_cast<int>(depthMapSize.y);
|
||||
if (p.depthMapSize.has_value()) {
|
||||
_shadowDepthTextureWidth = p.depthMapSize->x;
|
||||
_shadowDepthTextureHeight = p.depthMapSize->y;
|
||||
_dynamicDepthTextureRes = false;
|
||||
}
|
||||
else {
|
||||
@@ -212,13 +198,7 @@ ShadowComponent::ShadowComponent(const ghoul::Dictionary& dictionary)
|
||||
_dynamicDepthTextureRes = true;
|
||||
}
|
||||
|
||||
_saveDepthTexture.onChange([&]() { _executeDepthTextureSave = true; });
|
||||
|
||||
_viewDepthMap = false;
|
||||
|
||||
addProperty(_enabled);
|
||||
addProperty(_saveDepthTexture);
|
||||
addProperty(_distanceFraction);
|
||||
}
|
||||
|
||||
void ShadowComponent::initialize() {
|
||||
@@ -323,7 +303,7 @@ RenderData ShadowComponent::begin(const RenderData& data) {
|
||||
// Saves current state
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_currentFBO);
|
||||
global::renderEngine->openglStateCache().viewport(_mViewport);
|
||||
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _shadowFBO);
|
||||
GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE };
|
||||
glDrawBuffers(3, drawBuffers);
|
||||
|
||||
@@ -105,8 +105,6 @@ private:
|
||||
properties::IntProperty _distanceFraction;
|
||||
properties::BoolProperty _enabled;
|
||||
|
||||
ghoul::Dictionary _shadowMapDictionary;
|
||||
|
||||
int _shadowDepthTextureHeight = 4096;
|
||||
int _shadowDepthTextureWidth = 4096;
|
||||
bool _dynamicDepthTextureRes = true;
|
||||
|
||||
@@ -184,7 +184,8 @@ void IswaCygnet::render(const RenderData& data, RendererTasks&) {
|
||||
_data.spatialScale.x * _data.offset,
|
||||
_data.spatialScale.w
|
||||
);
|
||||
glm::vec3 position = glm::vec3(pposition) * static_cast<float>(pow(10.f, pposition.w));
|
||||
glm::vec3 position =
|
||||
glm::vec3(pposition) * static_cast<float>(pow(10.f, pposition.w));
|
||||
|
||||
// Activate shader
|
||||
_shader->activate();
|
||||
|
||||
Submodule modules/kameleon/ext/kameleon updated: 8a5e966659...606edb945b
@@ -22,8 +22,8 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_EXOPLANETS___RENDERABLEHABITABLEZONE___H__
|
||||
#define __OPENSPACE_MODULE_EXOPLANETS___RENDERABLEHABITABLEZONE___H__
|
||||
#ifndef __OPENSPACE_MODULE_SPACE___RENDERABLEHABITABLEZONE___H__
|
||||
#define __OPENSPACE_MODULE_SPACE___RENDERABLEHABITABLEZONE___H__
|
||||
|
||||
#include <modules/base/rendering/renderabledisc.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
@@ -72,4 +72,4 @@ private:
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_EXOPLANETS___RENDERABLEHABITABLEZONE___H__
|
||||
#endif // __OPENSPACE_MODULE_SPACE___RENDERABLEHABITABLEZONE___H__
|
||||
|
||||
@@ -307,7 +307,8 @@ namespace {
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(RenderableStars)]] Parameters {
|
||||
// The path to the SPECK file containing information about the stars being rendered
|
||||
// The path to the SPECK file containing information about the stars being
|
||||
// rendered
|
||||
std::filesystem::path speckFile [[codegen::key("File")]];
|
||||
|
||||
// [[codegen::verbatim(ColorTextureInfo.description)]]
|
||||
@@ -336,8 +337,8 @@ namespace {
|
||||
// loading. This can be used to trim the dataset's automatic value range
|
||||
std::optional<float> staticFilter;
|
||||
|
||||
// This is the value that is used to replace statically filtered values. Setting this
|
||||
// value only makes sense if 'StaticFilter' is 'true', as well
|
||||
// This is the value that is used to replace statically filtered values. Setting
|
||||
// this value only makes sense if 'StaticFilter' is 'true', as well
|
||||
std::optional<float> staticFilterReplacement;
|
||||
|
||||
// [[codegen::verbatim(MagnitudeExponentInfo.description)]]
|
||||
|
||||
@@ -34,19 +34,38 @@
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <optional>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeySource = "Source";
|
||||
constexpr const char* KeyTarget = "Target";
|
||||
constexpr const char* KeyInstrument = "Instrument";
|
||||
constexpr const char* KeyColor = "Color";
|
||||
constexpr const char* KeyColorStart = "Start";
|
||||
constexpr const char* KeyColorEnd = "End";
|
||||
|
||||
struct VBOData {
|
||||
float position[3];
|
||||
float color[4];
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(RenderableCrawlingLine)]] Parameters {
|
||||
// Denotes the SPICE name of the source of the renderable crawling line, for
|
||||
// example, the spacecraft
|
||||
std::string source;
|
||||
|
||||
// Denotes the SPICE name of the target of the crawling line
|
||||
std::string target;
|
||||
|
||||
// Denotes the SPICE name of the instrument that is used to render the crawling
|
||||
// line
|
||||
std::string instrument;
|
||||
|
||||
struct Color {
|
||||
// The color at the start of the line
|
||||
glm::vec4 start [[codegen::color()]];
|
||||
|
||||
// The color at the end of the line
|
||||
glm::vec4 end [[codegen::color()]];
|
||||
};
|
||||
// Specifies the colors that are used for the crawling line. One value determines
|
||||
// the starting color of the line, the second value is the color at the end
|
||||
Color color;
|
||||
};
|
||||
#include "renderablecrawlingline_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
// @TODO: This class is not properly working anymore and needs to be substantially
|
||||
@@ -56,76 +75,21 @@ namespace {
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation RenderableCrawlingLine::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"RenderableCrawlingLine",
|
||||
"newhorizons_renderable_crawlingline",
|
||||
{
|
||||
{
|
||||
KeySource,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"Denotes the SPICE name of the source of the renderable crawling line, "
|
||||
"for example, the space craft"
|
||||
},
|
||||
{
|
||||
KeyTarget,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"Denotes the SPICE name of the target of the crawling line"
|
||||
},
|
||||
{
|
||||
KeyInstrument,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"Denotes the SPICE name of the instrument that is used to render the "
|
||||
"crawling line"
|
||||
},
|
||||
{
|
||||
KeyColor,
|
||||
new TableVerifier({
|
||||
{
|
||||
KeyColorStart,
|
||||
new Color4Verifier,
|
||||
Optional::No,
|
||||
"The color at the start of the line",
|
||||
},
|
||||
{
|
||||
KeyColorEnd,
|
||||
new Color4Verifier,
|
||||
Optional::No,
|
||||
"The color at the end of the line"
|
||||
}
|
||||
}),
|
||||
Optional::No,
|
||||
"Specifies the colors that are used for the crawling line. One value "
|
||||
"determines the starting color of the line, the second value is the "
|
||||
"color at the end of the line."
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "newhorizons_renderable_crawlingline";
|
||||
return doc;
|
||||
}
|
||||
|
||||
RenderableCrawlingLine::RenderableCrawlingLine(const ghoul::Dictionary& dictionary)
|
||||
: Renderable(dictionary)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"RenderableCrawlingLine"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_source = dictionary.value<std::string>(KeySource);
|
||||
_target = dictionary.value<std::string>(KeyTarget);
|
||||
_instrumentName = dictionary.value<std::string>(KeyInstrument);
|
||||
|
||||
_lineColorBegin = dictionary.value<glm::dvec4>(
|
||||
std::string(KeyColor) + "." + KeyColorStart
|
||||
);
|
||||
|
||||
_lineColorEnd = dictionary.value<glm::dvec4>(
|
||||
std::string(KeyColor) + "." + KeyColorEnd
|
||||
);
|
||||
_source = p.source;
|
||||
_target = p.target;
|
||||
_instrumentName = p.instrument;
|
||||
_lineColorBegin = p.color.start;
|
||||
_lineColorEnd = p.color.end;
|
||||
}
|
||||
|
||||
bool RenderableCrawlingLine::isReady() const {
|
||||
|
||||
@@ -35,17 +35,10 @@
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <glm/gtx/projection.hpp>
|
||||
#include <optional>
|
||||
|
||||
namespace {
|
||||
constexpr const char* ProgramName = "FovProgram";
|
||||
constexpr const char* KeyBody = "Body";
|
||||
constexpr const char* KeyFrame = "Frame";
|
||||
constexpr const char* KeyInstrument = "Instrument";
|
||||
constexpr const char* KeyInstrumentName = "Name";
|
||||
constexpr const char* KeyInstrumentAberration = "Aberration";
|
||||
constexpr const char* KeyPotentialTargets = "PotentialTargets";
|
||||
constexpr const char* KeyFrameConversions = "FrameConversions";
|
||||
constexpr const char* KeyBoundsSimplification = "SimplifyBounds";
|
||||
|
||||
constexpr const std::array<const char*, 9> UniformNames = {
|
||||
"modelViewProjectionTransform", "defaultColorStart", "defaultColorEnd",
|
||||
@@ -153,142 +146,55 @@ namespace {
|
||||
}
|
||||
}
|
||||
// Needs support for std::map first for the frameConversions
|
||||
// struct [[codegen::Dictionary(RenderableFov)]] Parameters {
|
||||
// // The SPICE name of the source body for which the field of view should be
|
||||
// // rendered
|
||||
// std::string body;
|
||||
//
|
||||
// // The SPICE name of the source body's frame in which the field of view should be
|
||||
// // rendered
|
||||
// std::string frame;
|
||||
//
|
||||
// struct Instrument {
|
||||
// // The SPICE name of the instrument that is rendered
|
||||
// std::string name;
|
||||
//
|
||||
// // The aberration correction that is used for this field of view. The default
|
||||
// // is 'NONE'
|
||||
// std::optional<std::string> aberration [[codegen::inlist("NONE",
|
||||
// "LT", "LT+S", "CN", "CN+S", "XLT", "XLT+S", "XCN", "XCN+S")]];
|
||||
// };
|
||||
// // A table describing the instrument whose field of view should be rendered
|
||||
// Instrument instrument;
|
||||
//
|
||||
// // A list of potential targets (specified as SPICE names) that the field of view
|
||||
// // should be tested against
|
||||
// std::vector<std::string> potentialTargets;
|
||||
//
|
||||
// // A list of frame conversions that should be registered with the SpiceManager
|
||||
// std::optional<std::vector<std::string>> frameConversions;
|
||||
//
|
||||
// // [[codegen::verbatim(LineWidthInfo.description)]]
|
||||
// std::optional<double> lineWidth;
|
||||
//
|
||||
// // [[codegen::verbatim(StandoffDistanceInfo.description)]]
|
||||
// std::optional<double> standOffDistance;
|
||||
//
|
||||
// // If this value is set to 'true' the field-of-views bounds values will be
|
||||
// // simplified on load. Bound vectors will be removed if they are the strict linear
|
||||
// // interpolation between the two neighboring vectors. This value is disabled on
|
||||
// // default
|
||||
// std::optional<bool> simplifyBounds;
|
||||
// };
|
||||
//#include "renderablefov_codegen.cpp"
|
||||
struct [[codegen::Dictionary(RenderableFov)]] Parameters {
|
||||
// The SPICE name of the source body for which the field of view should be
|
||||
// rendered
|
||||
std::string body;
|
||||
|
||||
// The SPICE name of the source body's frame in which the field of view should be
|
||||
// rendered
|
||||
std::string frame;
|
||||
|
||||
struct Instrument {
|
||||
// The SPICE name of the instrument that is rendered
|
||||
std::string name;
|
||||
|
||||
// The aberration correction that is used for this field of view. The default
|
||||
// is 'NONE'
|
||||
std::optional<std::string> aberration [[codegen::inlist("NONE",
|
||||
"LT", "LT+S", "CN", "CN+S", "XLT", "XLT+S", "XCN", "XCN+S")]];
|
||||
};
|
||||
// A table describing the instrument whose field of view should be rendered
|
||||
Instrument instrument;
|
||||
|
||||
// A list of potential targets (specified as SPICE names) that the field of view
|
||||
// should be tested against
|
||||
std::vector<std::string> potentialTargets;
|
||||
|
||||
// A list of frame conversions that should be registered with the SpiceManager
|
||||
std::optional<std::map<std::string, std::string>> frameConversions;
|
||||
|
||||
// [[codegen::verbatim(LineWidthInfo.description)]]
|
||||
std::optional<float> lineWidth;
|
||||
|
||||
// [[codegen::verbatim(StandoffDistanceInfo.description)]]
|
||||
std::optional<float> standOffDistance;
|
||||
|
||||
// If this value is set to 'true' the field-of-views bounds values will be
|
||||
// simplified on load. Bound vectors will be removed if they are the strict linear
|
||||
// interpolation between the two neighboring vectors. This value is disabled on
|
||||
// default
|
||||
std::optional<bool> simplifyBounds;
|
||||
};
|
||||
#include "renderablefov_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation RenderableFov::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"RenderableFieldOfView",
|
||||
"newhorizons_renderable_fieldofview",
|
||||
{
|
||||
{
|
||||
KeyBody,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The SPICE name of the source body for which the field of view should be "
|
||||
"rendered."
|
||||
},
|
||||
{
|
||||
KeyFrame,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The SPICE name of the source body's frame in which the field of view "
|
||||
"should be rendered."
|
||||
},
|
||||
{
|
||||
KeyInstrument,
|
||||
new TableVerifier({
|
||||
{
|
||||
KeyInstrumentName,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The SPICE name of the instrument that is rendered"
|
||||
},
|
||||
{
|
||||
KeyInstrumentAberration,
|
||||
new StringInListVerifier({
|
||||
// Taken from SpiceManager::AberrationCorrection
|
||||
"NONE",
|
||||
"LT", "LT+S",
|
||||
"CN", "CN+S",
|
||||
"XLT", "XLT+S",
|
||||
"XCN", "XCN+S"
|
||||
}),
|
||||
Optional::Yes,
|
||||
"The aberration correction that is used for this field of view. "
|
||||
"The default is 'NONE'."
|
||||
}
|
||||
}),
|
||||
Optional::No,
|
||||
"A table describing the instrument whose field of view should be "
|
||||
"rendered."
|
||||
},
|
||||
{
|
||||
KeyPotentialTargets,
|
||||
new StringListVerifier,
|
||||
Optional::No,
|
||||
"A list of potential targets (specified as SPICE names) that the field "
|
||||
"of view should be tested against."
|
||||
},
|
||||
{
|
||||
KeyFrameConversions,
|
||||
new TableVerifier({
|
||||
{
|
||||
DocumentationEntry::Wildcard,
|
||||
new StringVerifier,
|
||||
Optional::No
|
||||
}
|
||||
}),
|
||||
Optional::Yes,
|
||||
"A list of frame conversions that should be registered with the "
|
||||
"SpiceManager."
|
||||
},
|
||||
{
|
||||
LineWidthInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LineWidthInfo.description
|
||||
},
|
||||
{
|
||||
StandoffDistanceInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
StandoffDistanceInfo.description
|
||||
},
|
||||
{
|
||||
KeyBoundsSimplification,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
"If this value is set to 'true' the field-of-views bounds values will be "
|
||||
"simplified on load. Bound vectors will be removed if they are the "
|
||||
"strict linear interpolation between the two neighboring vectors. This "
|
||||
"value is disabled on default."
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "newhorizons_renderable_fieldofview";
|
||||
return doc;
|
||||
}
|
||||
|
||||
|
||||
@@ -342,61 +248,37 @@ RenderableFov::RenderableFov(const ghoul::Dictionary& dictionary)
|
||||
}
|
||||
})
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"RenderableFov"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_instrument.spacecraft = dictionary.value<std::string>(KeyBody);
|
||||
_instrument.referenceFrame = dictionary.value<std::string>(KeyFrame);
|
||||
|
||||
_instrument.name = dictionary.value<std::string>(
|
||||
std::string(KeyInstrument) + "." + KeyInstrumentName
|
||||
);
|
||||
|
||||
std::string ia = std::string(KeyInstrument) + "." + KeyInstrumentAberration;
|
||||
if (dictionary.hasValue<std::string>(ia)) {
|
||||
const std::string& ac = dictionary.value<std::string>(ia);
|
||||
_instrument.aberrationCorrection = SpiceManager::AberrationCorrection(ac);
|
||||
_instrument.spacecraft = p.body;
|
||||
_instrument.referenceFrame = p.frame;
|
||||
_instrument.name = p.instrument.name;
|
||||
if (p.instrument.aberration.has_value()) {
|
||||
_instrument.aberrationCorrection = SpiceManager::AberrationCorrection(
|
||||
*p.instrument.aberration
|
||||
);
|
||||
}
|
||||
|
||||
ghoul::Dictionary pt = dictionary.value<ghoul::Dictionary>(KeyPotentialTargets);
|
||||
_instrument.potentialTargets.reserve(pt.size());
|
||||
for (size_t i = 1; i <= pt.size(); ++i) {
|
||||
std::string target = pt.value<std::string>(std::to_string(i));
|
||||
_instrument.potentialTargets.push_back(std::move(target));
|
||||
}
|
||||
_instrument.potentialTargets = p.potentialTargets;
|
||||
|
||||
if (dictionary.hasKey(KeyFrameConversions)) {
|
||||
ghoul::Dictionary fc = dictionary.value<ghoul::Dictionary>(KeyFrameConversions);
|
||||
for (std::string_view key : fc.keys()) {
|
||||
if (p.frameConversions.has_value()) {
|
||||
for (const std::pair<const std::string, std::string>& fc : *p.frameConversions) {
|
||||
global::moduleEngine->module<SpacecraftInstrumentsModule>()->addFrame(
|
||||
std::string(key),
|
||||
fc.value<std::string>(key)
|
||||
fc.first,
|
||||
fc.second
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(LineWidthInfo.identifier)) {
|
||||
_lineWidth = static_cast<float>(dictionary.value<double>(
|
||||
LineWidthInfo.identifier
|
||||
));
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(StandoffDistanceInfo.identifier)) {
|
||||
_standOffDistance = static_cast<float>(dictionary.value<double>(
|
||||
StandoffDistanceInfo.identifier
|
||||
));
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyBoundsSimplification)) {
|
||||
_simplifyBounds = dictionary.value<bool>(KeyBoundsSimplification);
|
||||
}
|
||||
|
||||
_lineWidth = p.lineWidth.value_or(_lineWidth);
|
||||
addProperty(_lineWidth);
|
||||
addProperty(_drawSolid);
|
||||
|
||||
_standOffDistance = p.standOffDistance.value_or(_standOffDistance);
|
||||
addProperty(_standOffDistance);
|
||||
|
||||
_simplifyBounds = p.simplifyBounds.value_or(_simplifyBounds);
|
||||
|
||||
addProperty(_drawSolid);
|
||||
|
||||
addProperty(_colors.defaultStart);
|
||||
addProperty(_colors.defaultEnd);
|
||||
|
||||
@@ -279,7 +279,6 @@ void RenderablePlaneProjection::updatePlane(const Image& img, double currentTime
|
||||
glm::vec3(projection[1]),
|
||||
glm::vec3(projection[2]),
|
||||
glm::vec3(projection[3])
|
||||
|
||||
};
|
||||
const GLfloat vertex_data[] = {
|
||||
// square of two triangles drawn within fov in target coordinates
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/opengl/textureconversion.h>
|
||||
#include <ghoul/opengl/textureunit.h>
|
||||
#include <optional>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "RenderablePlanetProjection";
|
||||
@@ -56,8 +57,6 @@ namespace {
|
||||
"boresight", "_radius", "_segments"
|
||||
};
|
||||
|
||||
constexpr const char* KeyGeometry = "Geometry";
|
||||
constexpr const char* KeyProjection = "Projection";
|
||||
constexpr const char* KeyRadius = "Geometry.Radius";
|
||||
constexpr const char* _mainFrame = "GALACTIC";
|
||||
|
||||
@@ -134,67 +133,42 @@ namespace {
|
||||
"Clear Projection Buffer",
|
||||
"Remove all pending projections from the buffer"
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(RenderablePlanetProjection)]] Parameters {
|
||||
// The geometry that is used for rendering this planet
|
||||
ghoul::Dictionary geometry [[codegen::reference("space_geometry_planet")]];
|
||||
|
||||
// Contains information about projecting onto this planet
|
||||
ghoul::Dictionary projection
|
||||
[[codegen::reference("newhorizons_projectioncomponent")]];
|
||||
|
||||
// [[codegen::verbatim(ColorTexturePathsInfo.description)]]
|
||||
std::vector<std::string> colorTexturePaths;
|
||||
|
||||
// [[codegen::verbatim(HeightTexturePathsInfo.description)]]
|
||||
std::vector<std::string> heightTexturePaths;
|
||||
|
||||
// [[codegen::verbatim(HeightExaggerationInfo.description)]]
|
||||
std::optional<float> heightExaggeration;
|
||||
|
||||
// [[codegen::verbatim(MeridianShiftInfo.description)]]
|
||||
std::optional<bool> meridianShift;
|
||||
|
||||
// [[codegen::verbatim(AmbientBrightnessInfo.description)]]
|
||||
std::optional<double> ambientBrightness;
|
||||
|
||||
// [[codegen::verbatim(MaxProjectionsPerFrameInfo.description)]]
|
||||
std::optional<int> maxProjectionsPerFrame;
|
||||
};
|
||||
#include "renderableplanetprojection_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation RenderablePlanetProjection::Documentation() {
|
||||
using namespace openspace::documentation;
|
||||
return {
|
||||
"Renderable Planet Projection",
|
||||
"newhorizons_renderable_planetprojection",
|
||||
{
|
||||
{
|
||||
KeyGeometry,
|
||||
new ReferencingVerifier("space_geometry_planet"),
|
||||
Optional::No,
|
||||
"The geometry that is used for rendering this planet.",
|
||||
},
|
||||
{
|
||||
KeyProjection,
|
||||
new ReferencingVerifier("newhorizons_projectioncomponent"),
|
||||
Optional::No,
|
||||
"Contains information about projecting onto this planet.",
|
||||
},
|
||||
{
|
||||
ColorTexturePathsInfo.identifier,
|
||||
new StringListVerifier,
|
||||
Optional::No,
|
||||
ColorTexturePathsInfo.description
|
||||
},
|
||||
{
|
||||
HeightTexturePathsInfo.identifier,
|
||||
new StringListVerifier,
|
||||
Optional::Yes,
|
||||
HeightTexturePathsInfo.description
|
||||
},
|
||||
{
|
||||
HeightExaggerationInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
HeightExaggerationInfo.description
|
||||
},
|
||||
{
|
||||
MeridianShiftInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
MeridianShiftInfo.description
|
||||
},
|
||||
{
|
||||
AmbientBrightnessInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
AmbientBrightnessInfo.description
|
||||
},
|
||||
{
|
||||
MaxProjectionsPerFrameInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
MaxProjectionsPerFrameInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "newhorizons_renderable_planetprojection";
|
||||
return doc;
|
||||
}
|
||||
|
||||
RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary& dict)
|
||||
@@ -210,43 +184,24 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary&
|
||||
, _projectionsInBuffer(ProjectionsInBufferInfo, 0, 1, 32)
|
||||
, _clearProjectionBuffer(ClearProjectionBufferInfo)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dict,
|
||||
"RenderablePlanetProjection"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dict);
|
||||
|
||||
ghoul::Dictionary geometryDictionary = dict.value<ghoul::Dictionary>(KeyGeometry);
|
||||
_geometry = planetgeometry::PlanetGeometry::createFromDictionary(geometryDictionary);
|
||||
|
||||
_projectionComponent.initialize(
|
||||
identifier(),
|
||||
dict.value<ghoul::Dictionary>(KeyProjection)
|
||||
);
|
||||
_geometry = planetgeometry::PlanetGeometry::createFromDictionary(p.geometry);
|
||||
_projectionComponent.initialize(identifier(), p.projection);
|
||||
|
||||
_colorTexturePaths.addOption(0, NoImageText);
|
||||
_colorTexturePaths.onChange([this](){ _colorTextureDirty = true; });
|
||||
addProperty(_colorTexturePaths);
|
||||
|
||||
if (dict.hasValue<ghoul::Dictionary>(ColorTexturePathsInfo.identifier)) {
|
||||
const ghoul::Dictionary& value = dict.value<ghoul::Dictionary>(
|
||||
ColorTexturePathsInfo.identifier
|
||||
for (const std::string& t : p.colorTexturePaths) {
|
||||
_colorTexturePaths.addOption(
|
||||
static_cast<int>(_colorTexturePaths.options().size()),
|
||||
t
|
||||
);
|
||||
|
||||
for (size_t i = 1; i <= value.size(); ++i) {
|
||||
std::string texture = absPath(value.value<std::string>(std::to_string(i)));
|
||||
|
||||
_colorTexturePaths.addOption(
|
||||
// as we started with 0, this works
|
||||
static_cast<int>(_colorTexturePaths.options().size()),
|
||||
texture
|
||||
);
|
||||
|
||||
_colorTexturePaths = static_cast<int>(
|
||||
_colorTexturePaths.options().size() - 1
|
||||
);
|
||||
}
|
||||
}
|
||||
_colorTexturePaths = static_cast<int>(
|
||||
_colorTexturePaths.options().size() - 1
|
||||
);
|
||||
|
||||
_addColorTexturePath.onChange([this]() {
|
||||
if (!_addColorTexturePath.value().empty()) {
|
||||
@@ -271,27 +226,15 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary&
|
||||
_heightMapTexturePaths.onChange([this]() { _heightMapTextureDirty = true; });
|
||||
addProperty(_heightMapTexturePaths);
|
||||
|
||||
|
||||
if (dict.hasValue<ghoul::Dictionary>(HeightTexturePathsInfo.identifier)) {
|
||||
const ghoul::Dictionary& value = dict.value<ghoul::Dictionary>(
|
||||
HeightTexturePathsInfo.identifier
|
||||
for (const std::string& t : p.heightTexturePaths) {
|
||||
_heightMapTexturePaths.addOption(
|
||||
static_cast<int>(_heightMapTexturePaths.options().size()),
|
||||
t
|
||||
);
|
||||
|
||||
for (size_t i = 1; i <= value.size(); ++i) {
|
||||
std::string texture = absPath(value.value<std::string>(std::to_string(i)));
|
||||
|
||||
_heightMapTexturePaths.addOption(
|
||||
// as we started with 0, this works
|
||||
static_cast<int>(_heightMapTexturePaths.options().size()),
|
||||
texture
|
||||
);
|
||||
|
||||
_heightMapTexturePaths = static_cast<int>(
|
||||
_heightMapTexturePaths.options().size() - 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_heightMapTexturePaths = static_cast<int>(
|
||||
_heightMapTexturePaths.options().size() - 1
|
||||
);
|
||||
_addHeightMapTexturePath.onChange([this]() {
|
||||
if (!_addHeightMapTexturePath.value().empty()) {
|
||||
_heightMapTexturePaths.addOption(
|
||||
@@ -308,11 +251,12 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary&
|
||||
});
|
||||
addProperty(_addHeightMapTexturePath);
|
||||
|
||||
_meridianShift = p.meridianShift.value_or(_meridianShift);
|
||||
addProperty(_meridianShift);
|
||||
|
||||
if (dict.hasValue<bool>(MeridianShiftInfo.identifier)) {
|
||||
_meridianShift = dict.value<bool>(MeridianShiftInfo.identifier);
|
||||
}
|
||||
|
||||
// @TODO (abock, 2021-03-26) Poking into the Geometry dictionary is not really
|
||||
// optimal as we don't have local control over how the dictionary is checked. We
|
||||
// should instead ask the geometry whether it has a radius or not
|
||||
double radius = std::pow(10.0, 9.0);
|
||||
if (dict.hasValue<double>(KeyRadius)) {
|
||||
radius = dict.value<double>(KeyRadius);
|
||||
@@ -322,25 +266,16 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary&
|
||||
addPropertySubOwner(_geometry.get());
|
||||
addPropertySubOwner(_projectionComponent);
|
||||
|
||||
if (dict.hasKey(HeightExaggerationInfo.identifier)) {
|
||||
_heightExaggeration = static_cast<float>(
|
||||
dict.value<double>(HeightExaggerationInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (dict.hasKey(MaxProjectionsPerFrameInfo.identifier)) {
|
||||
_maxProjectionsPerFrame = static_cast<int>(
|
||||
dict.value<double>(MaxProjectionsPerFrameInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
_heightExaggeration = p.heightExaggeration.value_or(_heightExaggeration);
|
||||
addProperty(_heightExaggeration);
|
||||
addProperty(_meridianShift);
|
||||
addProperty(_ambientBrightness);
|
||||
|
||||
|
||||
_maxProjectionsPerFrame = p.maxProjectionsPerFrame.value_or(_maxProjectionsPerFrame);
|
||||
addProperty(_maxProjectionsPerFrame);
|
||||
|
||||
addProperty(_ambientBrightness);
|
||||
addProperty(_projectionsInBuffer);
|
||||
|
||||
|
||||
_clearProjectionBuffer.onChange([this]() {
|
||||
_imageTimes.clear();
|
||||
_projectionsInBuffer = static_cast<int>(_imageTimes.size());
|
||||
|
||||
@@ -38,39 +38,29 @@
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "HttpSynchronization";
|
||||
|
||||
constexpr const char* KeyIdentifier = "Identifier";
|
||||
constexpr const char* KeyVersion = "Version";
|
||||
|
||||
constexpr const char* TempSuffix = ".tmp";
|
||||
|
||||
constexpr const char* QueryKeyIdentifier = "identifier";
|
||||
constexpr const char* QueryKeyFileVersion = "file_version";
|
||||
constexpr const char* QueryKeyApplicationVersion = "application_version";
|
||||
constexpr const int ApplicationVersion = 1;
|
||||
|
||||
struct [[codegen::Dictionary(HttpSynchronization)]] Parameters {
|
||||
// A unique identifier for this resource
|
||||
std::string identifier;
|
||||
|
||||
// The version of this resource
|
||||
int version;
|
||||
};
|
||||
#include "httpsynchronization_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation HttpSynchronization::Documentation() {
|
||||
using namespace openspace::documentation;
|
||||
return {
|
||||
"HttpSynchronization",
|
||||
"http_synchronization",
|
||||
{
|
||||
{
|
||||
KeyIdentifier,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"A unique identifier for this resource"
|
||||
},
|
||||
{
|
||||
KeyVersion,
|
||||
new IntVerifier,
|
||||
Optional::No,
|
||||
"The version of this resource"
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "http_synchronization";
|
||||
return doc;
|
||||
}
|
||||
|
||||
HttpSynchronization::HttpSynchronization(const ghoul::Dictionary& dict,
|
||||
@@ -81,14 +71,10 @@ HttpSynchronization::HttpSynchronization(const ghoul::Dictionary& dict,
|
||||
, _synchronizationRoot(std::move(synchronizationRoot))
|
||||
, _synchronizationRepositories(std::move(synchronizationRepositories))
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dict,
|
||||
"HttpSynchronization"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dict);
|
||||
|
||||
_identifier = dict.value<std::string>(KeyIdentifier);
|
||||
_version = static_cast<int>(dict.value<double>(KeyVersion));
|
||||
_identifier = p.identifier;
|
||||
_version = p.version;
|
||||
}
|
||||
|
||||
HttpSynchronization::~HttpSynchronization() {
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
#include <fstream>
|
||||
#include <numeric>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyUrl = "Url";
|
||||
@@ -46,61 +48,44 @@ namespace {
|
||||
constexpr const char* KeyFilename = "Filename";
|
||||
|
||||
constexpr const char* TempSuffix = ".tmp";
|
||||
|
||||
struct [[codegen::Dictionary(UrlSynchronization)]] Parameters {
|
||||
// The URL or urls from where the files are downloaded. If multiple URLs are
|
||||
// provided, all files will be downloaded to the same directory
|
||||
std::variant<std::string, std::vector<std::string>> url;
|
||||
|
||||
// This optional identifier will be part of the used folder structure and, if
|
||||
// provided, can be used to manually find the downloaded folder in the
|
||||
// synchronization folder. If this value is not specified, 'UseHash' has to be set
|
||||
// to 'true'
|
||||
std::optional<std::string> identifier;
|
||||
|
||||
// If this value is set to 'true' and it is not overwritten by the global
|
||||
// settings, the file(s) pointed to by this URLSynchronization will always be
|
||||
// downloaded, thus overwriting the local files. This is useful for files that are
|
||||
// updated regularly remotely and should be fetch at every startup
|
||||
std::optional<bool> forceOverride [[codegen::key("override")]];
|
||||
|
||||
// If this value is set to 'true' (the default), the hash of the URL is appended
|
||||
// to the directory name to produce a unique directory under all circumstances. If
|
||||
// this is not desired, the URLSynchronization use the bare directory name alone
|
||||
// if this value is 'false'. If this value is 'false', the identifier has to be
|
||||
// specified
|
||||
std::optional<bool> useHash;
|
||||
|
||||
// Optional to provide filename to override the one which is otherwise
|
||||
// automatically created from the url
|
||||
std::optional<std::string> filename;
|
||||
};
|
||||
#include "urlsynchronization_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation UrlSynchronization::Documentation() {
|
||||
using namespace openspace::documentation;
|
||||
return {
|
||||
"Url Synchronization",
|
||||
"sync_synchronization_url",
|
||||
{
|
||||
{
|
||||
KeyUrl,
|
||||
new OrVerifier({ new StringVerifier, new StringListVerifier }),
|
||||
Optional::No,
|
||||
"The URL or urls from where the files are downloaded. If multiple URLs "
|
||||
"are provided, all files will be downloaded to the same directory."
|
||||
},
|
||||
{
|
||||
KeyIdentifier,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"This optional identifier will be part of the used folder structure and, "
|
||||
"if provided, can be used to manually find the downloaded folder in the "
|
||||
"synchronization folder. If this value is not specified, 'UseHash' has "
|
||||
"to be set to 'true'."
|
||||
},
|
||||
{
|
||||
KeyOverride,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
"If this value is set to 'true' and it is not overwritten by the global "
|
||||
"settings, the file(s) pointed to by this URLSynchronization will always "
|
||||
"be downloaded, thus overwriting the local files. This is useful for "
|
||||
"files that are updated regularly remotely and should be fetch at every "
|
||||
"startup."
|
||||
},
|
||||
{
|
||||
KeyUseHash,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
"If this value is set to 'true' (the default), the hash of the URL is "
|
||||
"appended to the directory name to produce a unique directory under all "
|
||||
"circumstances. If this is not desired, the URLSynchronization use the "
|
||||
"bare directory name alone if this value is 'false'. If this value is "
|
||||
"'false', the identifier has to be specified."
|
||||
},
|
||||
{
|
||||
KeyFilename,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"Optional to provide filename to override the one which is otherwise "
|
||||
"automatically created from the url. "
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "sync_synchronization_url";
|
||||
return doc;
|
||||
}
|
||||
|
||||
UrlSynchronization::UrlSynchronization(const ghoul::Dictionary& dict,
|
||||
@@ -108,43 +93,33 @@ UrlSynchronization::UrlSynchronization(const ghoul::Dictionary& dict,
|
||||
: ResourceSynchronization(dict)
|
||||
, _synchronizationRoot(std::move(synchronizationRoot))
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dict,
|
||||
"UrlSynchroniztion"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dict);
|
||||
|
||||
if (dict.hasValue<std::string>(KeyUrl)) {
|
||||
_urls.push_back(dict.value<std::string>(KeyUrl));
|
||||
if (std::holds_alternative<std::string>(p.url)) {
|
||||
_urls.push_back(std::get<std::string>(p.url));
|
||||
|
||||
}
|
||||
else if (std::holds_alternative<std::vector<std::string>>(p.url)) {
|
||||
_urls = std::get<std::vector<std::string>>(p.url);
|
||||
}
|
||||
else {
|
||||
ghoul::Dictionary urls = dict.value<ghoul::Dictionary>(KeyUrl);
|
||||
for (size_t i = 1; i <= urls.size(); ++i) {
|
||||
std::string url = urls.value<std::string>(std::to_string(i));
|
||||
_urls.push_back(std::move(url));
|
||||
}
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
|
||||
if (dict.hasValue<std::string>(KeyFilename)) {
|
||||
_filename = dict.value<std::string>(KeyFilename);
|
||||
}
|
||||
_filename = p.filename.value_or(_filename);
|
||||
|
||||
bool useHash = true;
|
||||
if (dict.hasValue<bool>(KeyUseHash)) {
|
||||
useHash = dict.value<bool>(KeyUseHash);
|
||||
}
|
||||
bool useHash = p.useHash.value_or(true);
|
||||
|
||||
// We just merge all of the URLs together to generate a hash, it's not as stable to
|
||||
// reordering URLs, but every other solution would be more error prone
|
||||
std::string urlConcat = std::accumulate(_urls.begin(), _urls.end(), std::string());
|
||||
size_t hash = std::hash<std::string>{}(urlConcat);
|
||||
if (dict.hasValue<std::string>(KeyIdentifier)) {
|
||||
std::string ident = dict.value<std::string>(KeyIdentifier);
|
||||
if (p.identifier.has_value()) {
|
||||
if (useHash) {
|
||||
_identifier = std::move(ident) + "(" + std::to_string(hash) + ")";
|
||||
_identifier = *p.identifier + "(" + std::to_string(hash) + ")";
|
||||
}
|
||||
else {
|
||||
_identifier = std::move(ident);
|
||||
_identifier = *p.identifier;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -154,17 +129,15 @@ UrlSynchronization::UrlSynchronization(const ghoul::Dictionary& dict,
|
||||
else {
|
||||
documentation::TestResult res;
|
||||
res.success = false;
|
||||
res.offenses.push_back({
|
||||
std::string(KeyIdentifier) + "|" + KeyUseHash,
|
||||
documentation::TestResult::Offense::Reason::MissingKey
|
||||
});
|
||||
documentation::TestResult::Offense o;
|
||||
o.offender = std::string(KeyIdentifier) + "|" + KeyUseHash;
|
||||
o.reason = documentation::TestResult::Offense::Reason::MissingKey;
|
||||
res.offenses.push_back(o);
|
||||
throw documentation::SpecificationError(std::move(res), "UrlSynchronization");
|
||||
}
|
||||
}
|
||||
|
||||
if (dict.hasValue<bool>(KeyOverride)) {
|
||||
_forceOverride = dict.value<bool>(KeyOverride);
|
||||
}
|
||||
_forceOverride = p.forceOverride.value_or(_forceOverride);
|
||||
}
|
||||
|
||||
UrlSynchronization::~UrlSynchronization() {
|
||||
@@ -193,7 +166,6 @@ void UrlSynchronization::start() {
|
||||
std::vector<std::unique_ptr<AsyncHttpFileDownload>> downloads;
|
||||
|
||||
for (const std::string& url : _urls) {
|
||||
|
||||
if (_filename.empty()) {
|
||||
const size_t lastSlash = url.find_last_of('/');
|
||||
std::string lastPartOfUrl = url.substr(lastSlash + 1);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
@@ -56,36 +57,26 @@ namespace {
|
||||
"Property to define a custom unit descriptor to use to describe the distance "
|
||||
"value. Defaults to the units SI descriptor if not specified."
|
||||
};
|
||||
}
|
||||
|
||||
struct [[codegen::Dictionary(RenderableDistanceLabel)]] Parameters {
|
||||
// [[codegen::verbatim(NodeLineInfo.description)]]
|
||||
std::string nodeLine;
|
||||
|
||||
// [[codegen::verbatim(DistanceUnitInfo.description)]]
|
||||
std::optional<int> distanceUnit;
|
||||
|
||||
// [[codegen::verbatim(CustomUnitDescriptorInfo.description)]]
|
||||
std::optional<std::string> customUnitDescriptor;
|
||||
};
|
||||
#include "renderabledistancelabel_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation RenderableDistanceLabel::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"Renderable Distance Label",
|
||||
"vislab_renderable_distance_label",
|
||||
{
|
||||
{
|
||||
NodeLineInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
NodeLineInfo.description
|
||||
},
|
||||
{
|
||||
DistanceUnitInfo.identifier,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
DistanceUnitInfo.description
|
||||
},
|
||||
{
|
||||
CustomUnitDescriptorInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
CustomUnitDescriptorInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "vislab_renderable_distance_label";
|
||||
return doc;
|
||||
}
|
||||
|
||||
RenderableDistanceLabel::RenderableDistanceLabel(const ghoul::Dictionary& dictionary)
|
||||
@@ -94,27 +85,16 @@ RenderableDistanceLabel::RenderableDistanceLabel(const ghoul::Dictionary& dictio
|
||||
, _distanceUnit(DistanceUnitInfo, 1, 0, 11)
|
||||
, _customUnitDescriptor(CustomUnitDescriptorInfo)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"RenderableDistanceLabel"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
if (dictionary.hasKey(NodeLineInfo.identifier)) {
|
||||
_nodelineId = dictionary.value<std::string>(NodeLineInfo.identifier);
|
||||
addProperty(_nodelineId);
|
||||
}
|
||||
if (dictionary.hasKey(DistanceUnitInfo.identifier)) {
|
||||
_distanceUnit = static_cast<int>(
|
||||
dictionary.value<double>(DistanceUnitInfo.identifier)
|
||||
);
|
||||
addProperty(_distanceUnit);
|
||||
}
|
||||
if (dictionary.hasKey(CustomUnitDescriptorInfo.identifier)) {
|
||||
_customUnitDescriptor =
|
||||
dictionary.value<std::string>(CustomUnitDescriptorInfo.identifier);
|
||||
addProperty(_customUnitDescriptor);
|
||||
}
|
||||
_nodelineId = p.nodeLine;
|
||||
addProperty(_nodelineId);
|
||||
|
||||
_distanceUnit = p.distanceUnit.value_or(_distanceUnit);
|
||||
addProperty(_distanceUnit);
|
||||
|
||||
_customUnitDescriptor = p.customUnitDescriptor.value_or(_customUnitDescriptor);
|
||||
addProperty(_customUnitDescriptor);
|
||||
}
|
||||
|
||||
void RenderableDistanceLabel::update(const UpdateData&) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -28,20 +28,35 @@
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/util/time.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
#include <optional>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyDimensions = "Dimensions";
|
||||
constexpr const char* KeyLowerDomainBound = "LowerDomainBound";
|
||||
constexpr const char* KeyUpperDomainBound = "UpperDomainBound";
|
||||
struct [[codegen::Dictionary(RawVolumeMetaData)]] Parameters {
|
||||
// Specifies the number of grid cells in each dimension
|
||||
glm::ivec3 dimensions;
|
||||
|
||||
constexpr const char* KeyMinValue = "MinValue";
|
||||
constexpr const char* KeyMaxValue = "MaxValue";
|
||||
// Specifies the unit used to specity the domain
|
||||
std::optional<std::string> domainUnit;
|
||||
|
||||
constexpr const char* KeyTime = "Time";
|
||||
constexpr const char* KeyDomainUnit = "DomainUnit";
|
||||
constexpr const char* KeyValueUnit = "ValueUnit";
|
||||
// Specifies the lower domain bounds in the model coordinate system
|
||||
std::optional<glm::vec3> lowerDomainBound;
|
||||
|
||||
constexpr const char* KeyGridType = "GridType";
|
||||
// Specifies the upper domain bounds in the model coordinate system
|
||||
std::optional<glm::vec3> upperDomainBound;
|
||||
|
||||
// Specifies the time on the format YYYY-MM-DDTHH:MM:SS.000Z
|
||||
std::optional<std::string> time;
|
||||
|
||||
// Specifies the unit used to specity the value
|
||||
std::optional<std::string> valueUnit;
|
||||
|
||||
// Specifies the minimum value stored in the volume
|
||||
std::optional<float> minValue;
|
||||
|
||||
// Specifies the maximum value stored in the volume
|
||||
std::optional<float> maxValue;
|
||||
};
|
||||
#include "rawvolumemetadata_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace::volume {
|
||||
@@ -49,51 +64,53 @@ namespace openspace::volume {
|
||||
RawVolumeMetadata RawVolumeMetadata::createFromDictionary(
|
||||
const ghoul::Dictionary& dictionary)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"RawVolumeMetadata"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
RawVolumeMetadata metadata;
|
||||
metadata.dimensions = dictionary.value<glm::dvec3>(KeyDimensions);
|
||||
metadata.dimensions = p.dimensions;
|
||||
|
||||
metadata.hasDomainBounds = dictionary.hasValue<glm::dvec3>(KeyLowerDomainBound) &&
|
||||
dictionary.hasValue<glm::dvec3>(KeyUpperDomainBound);
|
||||
metadata.hasDomainBounds =
|
||||
p.lowerDomainBound.has_value() &&
|
||||
p.upperDomainBound.has_value();
|
||||
|
||||
if (metadata.hasDomainBounds) {
|
||||
metadata.lowerDomainBound = dictionary.value<glm::dvec3>(KeyLowerDomainBound);
|
||||
metadata.upperDomainBound = dictionary.value<glm::dvec3>(KeyUpperDomainBound);
|
||||
metadata.lowerDomainBound = *p.lowerDomainBound;
|
||||
metadata.upperDomainBound = *p.upperDomainBound;
|
||||
}
|
||||
metadata.hasDomainUnit = static_cast<float>(
|
||||
dictionary.hasValue<double>(KeyDomainUnit)
|
||||
);
|
||||
metadata.hasDomainUnit = p.domainUnit.has_value();
|
||||
if (metadata.hasDomainUnit) {
|
||||
metadata.domainUnit = dictionary.value<std::string>(KeyDomainUnit);
|
||||
metadata.domainUnit = *p.domainUnit;
|
||||
}
|
||||
|
||||
metadata.hasValueRange = dictionary.hasValue<double>(KeyMinValue) &&
|
||||
dictionary.hasValue<double>(KeyMaxValue);
|
||||
|
||||
metadata.hasValueRange = p.minValue.has_value() && p.maxValue.has_value();
|
||||
if (metadata.hasValueRange) {
|
||||
metadata.minValue = static_cast<float>(dictionary.value<double>(KeyMinValue));
|
||||
metadata.maxValue = static_cast<float>(dictionary.value<double>(KeyMaxValue));
|
||||
metadata.minValue = *p.minValue;
|
||||
metadata.maxValue = *p.maxValue;
|
||||
}
|
||||
metadata.hasValueUnit = static_cast<float>(dictionary.hasValue<double>(KeyValueUnit));
|
||||
metadata.hasValueUnit = p.valueUnit.has_value();
|
||||
if (metadata.hasValueUnit) {
|
||||
metadata.valueUnit = dictionary.value<std::string>(KeyValueUnit);
|
||||
metadata.valueUnit = *p.valueUnit;
|
||||
}
|
||||
|
||||
metadata.hasTime = dictionary.hasValue<std::string>(KeyTime);
|
||||
metadata.hasTime = p.time.has_value();
|
||||
if (metadata.hasTime) {
|
||||
std::string timeString = dictionary.value<std::string>(KeyTime);
|
||||
metadata.time = Time::convertTime(timeString);
|
||||
metadata.time = Time::convertTime(*p.time);
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
ghoul::Dictionary RawVolumeMetadata::dictionary() {
|
||||
constexpr const char* KeyDimensions = "Dimensions";
|
||||
constexpr const char* KeyLowerDomainBound = "LowerDomainBound";
|
||||
constexpr const char* KeyUpperDomainBound = "UpperDomainBound";
|
||||
constexpr const char* KeyMinValue = "MinValue";
|
||||
constexpr const char* KeyMaxValue = "MaxValue";
|
||||
constexpr const char* KeyTime = "Time";
|
||||
constexpr const char* KeyDomainUnit = "DomainUnit";
|
||||
constexpr const char* KeyValueUnit = "ValueUnit";
|
||||
constexpr const char* KeyGridType = "GridType";
|
||||
|
||||
ghoul::Dictionary dict;
|
||||
dict.setValue(KeyDimensions, glm::dvec3(dimensions));
|
||||
dict.setValue(KeyGridType, gridTypeToString(gridType));
|
||||
@@ -126,61 +143,9 @@ ghoul::Dictionary RawVolumeMetadata::dictionary() {
|
||||
}
|
||||
|
||||
documentation::Documentation RawVolumeMetadata::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"RawVolumeMetadata",
|
||||
"volume_rawvolumemetadata",
|
||||
{
|
||||
{
|
||||
KeyDimensions,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::No,
|
||||
"Specifies the number of grid cells in each dimension",
|
||||
},
|
||||
{
|
||||
KeyDomainUnit,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies the unit used to specity the domain",
|
||||
},
|
||||
{
|
||||
KeyLowerDomainBound,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::Yes,
|
||||
"Specifies the lower domain bounds in the model coordinate system",
|
||||
},
|
||||
{
|
||||
KeyUpperDomainBound,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::Yes,
|
||||
"Specifies the upper domain bounds in the model coordinate system",
|
||||
},
|
||||
{
|
||||
KeyTime,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies the time on the format YYYY-MM-DDTHH:MM:SS.000Z",
|
||||
},
|
||||
{
|
||||
KeyValueUnit,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies the unit used to specity the value",
|
||||
},
|
||||
{
|
||||
KeyMinValue,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies the minimum value stored in the volume"
|
||||
},
|
||||
{
|
||||
KeyMaxValue,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies the maximum value stored in the volume"
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "volume_rawvolumemetadata";
|
||||
return doc;
|
||||
}
|
||||
|
||||
} // namespace openspace::volume
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/util/time.h>
|
||||
#include <openspace/util/spicemanager.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/filesystem/file.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
@@ -37,7 +38,6 @@
|
||||
#include <ghoul/lua/lua_helper.h>
|
||||
#include <ghoul/misc/dictionaryluaformatter.h>
|
||||
#include <ghoul/misc/defer.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace {
|
||||
@@ -48,41 +48,65 @@ namespace {
|
||||
constexpr const char* KeyValueFunction = "ValueFunction";
|
||||
constexpr const char* KeyLowerDomainBound = "LowerDomainBound";
|
||||
constexpr const char* KeyUpperDomainBound = "UpperDomainBound";
|
||||
|
||||
struct [[codegen::Dictionary(GenerateRawVolumeTask)]] Parameters {
|
||||
// The Lua function used to compute the cell values
|
||||
std::string valueFunction [[codegen::annotation("A Lua expression that returns a "
|
||||
"function taking three numbers as arguments (x, y, z) and returning a "
|
||||
"number")]];
|
||||
|
||||
// The raw volume file to export data to
|
||||
std::string rawVolumeOutput [[codegen::annotation("A valid filepath")]];
|
||||
|
||||
// The lua dictionary file to export metadata to
|
||||
std::string dictionaryOutput [[codegen::annotation("A valid filepath")]];
|
||||
|
||||
// The timestamp that is written to the metadata of this volume
|
||||
std::string time;
|
||||
|
||||
// A vector representing the number of cells in each dimension
|
||||
glm::ivec3 dimensions;
|
||||
|
||||
// A vector representing the lower bound of the domain
|
||||
glm::dvec3 lowerDomainBound;
|
||||
|
||||
// A vector representing the upper bound of the domain
|
||||
glm::dvec3 upperDomainBound;
|
||||
};
|
||||
#include "generaterawvolumetask_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace::volume {
|
||||
|
||||
GenerateRawVolumeTask::GenerateRawVolumeTask(const ghoul::Dictionary& dictionary) {
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
documentation(),
|
||||
dictionary,
|
||||
"GenerateRawVolumeTask"
|
||||
);
|
||||
documentation::Documentation GenerateRawVolumeTask::documentation() {
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "generate_raw_volume_task";
|
||||
return doc;
|
||||
}
|
||||
|
||||
_rawVolumeOutputPath = absPath(dictionary.value<std::string>(KeyRawVolumeOutput));
|
||||
_dictionaryOutputPath = absPath(dictionary.value<std::string>(KeyDictionaryOutput));
|
||||
_dimensions = glm::uvec3(dictionary.value<glm::dvec3>(KeyDimensions));
|
||||
_time = dictionary.value<std::string>(KeyTime);
|
||||
_valueFunctionLua = dictionary.value<std::string>(KeyValueFunction);
|
||||
_lowerDomainBound = dictionary.value<glm::dvec3>(KeyLowerDomainBound);
|
||||
_upperDomainBound = dictionary.value<glm::dvec3>(KeyUpperDomainBound);
|
||||
GenerateRawVolumeTask::GenerateRawVolumeTask(const ghoul::Dictionary& dictionary) {
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_rawVolumeOutputPath = absPath(p.rawVolumeOutput);
|
||||
_dictionaryOutputPath = absPath(p.dictionaryOutput);
|
||||
_dimensions = p.dimensions;
|
||||
_time = p.time;
|
||||
_valueFunctionLua = p.valueFunction;
|
||||
_lowerDomainBound = p.lowerDomainBound;
|
||||
_upperDomainBound = p.upperDomainBound;
|
||||
}
|
||||
|
||||
std::string GenerateRawVolumeTask::description() {
|
||||
return "Generate a raw volume with dimenstions: (" +
|
||||
std::to_string(_dimensions.x) + ", " +
|
||||
std::to_string(_dimensions.y) + ", " +
|
||||
std::to_string(_dimensions.z) + "). " +
|
||||
"For each cell, set the value by evaluating the lua function: " +
|
||||
"`" + _valueFunctionLua + "`, with three arguments (x, y, z) ranging from " +
|
||||
"(" + std::to_string(_lowerDomainBound.x) + ", "
|
||||
+ std::to_string(_lowerDomainBound.y) + ", " +
|
||||
std::to_string(_lowerDomainBound.z) + ") to (" +
|
||||
std::to_string(_upperDomainBound.x) + ", " +
|
||||
std::to_string(_upperDomainBound.y) + ", " +
|
||||
std::to_string(_upperDomainBound.z) + ")." +
|
||||
"Write raw volume data into " + _rawVolumeOutputPath +
|
||||
" and dictionary with metadata to " + _dictionaryOutputPath;
|
||||
return fmt::format(
|
||||
"Generate a raw volume with dimenstions: ({}, {}, {}). For each cell, set the "
|
||||
"value by evaluating the lua function: `{}`, with three arguments (x, y, z) "
|
||||
"ranging from ({}, {}, {}) to ({}, {}, {}). Write raw volume data into {} and "
|
||||
"dictionary with metadata to {}",
|
||||
_dimensions.x, _dimensions.y, _dimensions.z, _valueFunctionLua,
|
||||
_lowerDomainBound.x, _lowerDomainBound.y, _lowerDomainBound.z,
|
||||
_upperDomainBound.x, _upperDomainBound.y, _upperDomainBound.z,
|
||||
_rawVolumeOutputPath, _dictionaryOutputPath
|
||||
);
|
||||
}
|
||||
|
||||
void GenerateRawVolumeTask::perform(const Task::ProgressCallback& progressCallback) {
|
||||
@@ -184,51 +208,4 @@ void GenerateRawVolumeTask::perform(const Task::ProgressCallback& progressCallba
|
||||
progressCallback(1.0f);
|
||||
}
|
||||
|
||||
documentation::Documentation GenerateRawVolumeTask::documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"GenerateRawVolumeTask",
|
||||
"generate_raw_volume_task",
|
||||
{
|
||||
{
|
||||
KeyValueFunction,
|
||||
new StringAnnotationVerifier("A lua expression that returns a function "
|
||||
"taking three numbers as arguments (x, y, z) and returning a number."),
|
||||
Optional::No,
|
||||
"The lua function used to compute the cell values",
|
||||
},
|
||||
{
|
||||
KeyRawVolumeOutput,
|
||||
new StringAnnotationVerifier("A valid filepath"),
|
||||
Optional::No,
|
||||
"The raw volume file to export data to",
|
||||
},
|
||||
{
|
||||
KeyDictionaryOutput,
|
||||
new StringAnnotationVerifier("A valid filepath"),
|
||||
Optional::No,
|
||||
"The lua dictionary file to export metadata to",
|
||||
},
|
||||
{
|
||||
KeyDimensions,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::No,
|
||||
"A vector representing the number of cells in each dimension",
|
||||
},
|
||||
{
|
||||
KeyLowerDomainBound,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::No,
|
||||
"A vector representing the lower bound of the domain"
|
||||
},
|
||||
{
|
||||
KeyUpperDomainBound,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::No,
|
||||
"A vector representing the upper bound of the domain"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace openspace::volume
|
||||
|
||||
@@ -229,18 +229,20 @@ ScreenSpaceRotation = { 0.0, 0.0, 0.0 }
|
||||
|
||||
RenderingMethod = "Framebuffer"
|
||||
OpenGLDebugContext = {
|
||||
Activate = true,
|
||||
FilterIdentifier = {
|
||||
{ Type = "Other", Source = "API", Identifier = 131185 },
|
||||
-- Buffer performance warning: "copied/moved from VIDEO memory to HOST memory"
|
||||
{ Type = "Performance", Source = "API", Identifier = 131186 },
|
||||
-- API_ID_LINE_WIDTH deprecated behavior warning has been generated
|
||||
{ Type = "Deprecated", Source = "API", Identifier = 7 },
|
||||
-- Program/shader state performance warning: Vertex shader in program %i is being recompiled based on GL state.
|
||||
{ Type = "Performance", Source = "API", Identifier = 131218 },
|
||||
-- This is getting a bit wordy
|
||||
{ Type = "Push group", Source = "Application", Identifier = 0 },
|
||||
{ Type = "Pop group", Source = "Application", Identifier = 0 },
|
||||
Activate = true,
|
||||
FilterIdentifier = {
|
||||
{ Type = "Other", Source = "API", Identifier = 131185 },
|
||||
-- API_ID_RECOMPILE_FRAGMENT_SHADER performance warning has been generated. Fragment shader recompiled due to state change
|
||||
{ Type = "Performance", Source = "API", Identifier = 2 },
|
||||
-- Buffer performance warning: "copied/moved from VIDEO memory to HOST memory"
|
||||
{ Type = "Performance", Source = "API", Identifier = 131186 },
|
||||
-- API_ID_LINE_WIDTH deprecated behavior warning has been generated
|
||||
{ Type = "Deprecated", Source = "API", Identifier = 7 },
|
||||
-- Program/shader state performance warning: Vertex shader in program %i is being recompiled based on GL state.
|
||||
{ Type = "Performance", Source = "API", Identifier = 131218 },
|
||||
-- This is getting a bit wordy
|
||||
{ Type = "Push group", Source = "Application", Identifier = 0 },
|
||||
{ Type = "Pop group", Source = "Application", Identifier = 0 },
|
||||
},
|
||||
-- FilterSeverity = { }
|
||||
}
|
||||
|
||||
@@ -161,7 +161,6 @@ set(OPENSPACE_SOURCE
|
||||
${OPENSPACE_BASE_DIR}/src/scene/sceneinitializer.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/scene/scenelicensewriter.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode_doc.inl
|
||||
${OPENSPACE_BASE_DIR}/src/scene/timeframe.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/scene/translation.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/scripting/lualibrary.cpp
|
||||
@@ -208,6 +207,10 @@ if (APPLE)
|
||||
${OPENSPACE_SOURCE}
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/touchbar.mm
|
||||
)
|
||||
set_source_files_properties(
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/touchbar.mm
|
||||
PROPERTIES SKIP_PRECOMPILE_HEADERS ON
|
||||
)
|
||||
endif ()
|
||||
set(OPENSPACE_HEADER
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/json.h
|
||||
|
||||
@@ -140,21 +140,6 @@ 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))
|
||||
|
||||
@@ -141,7 +141,9 @@ TestResult IntVerifier::operator()(const ghoul::Dictionary& dict,
|
||||
{
|
||||
if (dict.hasValue<int>(key)) {
|
||||
// We have a key and the value is int, we are done
|
||||
return { true, {}, {} };
|
||||
TestResult res;
|
||||
res.success = true;
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
if (dict.hasKey(key)) {
|
||||
@@ -151,23 +153,39 @@ TestResult IntVerifier::operator()(const ghoul::Dictionary& dict,
|
||||
double intPart;
|
||||
bool isInt = modf(value, &intPart) == 0.0;
|
||||
if (isInt) {
|
||||
return { true, {}, {} };
|
||||
TestResult res;
|
||||
res.success = true;
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
return {
|
||||
false,
|
||||
{ { key, TestResult::Offense::Reason::WrongType } },
|
||||
{}
|
||||
};
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If we don't have a double value, we cannot have an int value
|
||||
return { false, {{ key, TestResult::Offense::Reason::WrongType }}, {} };
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return { false, {{ key, TestResult::Offense::Reason::MissingKey }}, {} };
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::MissingKey;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -317,17 +335,26 @@ TestResult Color3Verifier::operator()(const ghoul::Dictionary& dictionary,
|
||||
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 });
|
||||
TestResult::Offense o;
|
||||
o.offender = key + ".x";
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
res.offenses.push_back(o);
|
||||
}
|
||||
|
||||
if (values.y < 0.0 || values.y > 1.0) {
|
||||
res.success = false;
|
||||
res.offenses.push_back({ key + ".y", TestResult::Offense::Reason::Verification });
|
||||
TestResult::Offense o;
|
||||
o.offender = key + ".y";
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
res.offenses.push_back(o);
|
||||
}
|
||||
|
||||
if (values.z < 0.0 || values.z > 1.0) {
|
||||
res.success = false;
|
||||
res.offenses.push_back({ key + ".z", TestResult::Offense::Reason::Verification });
|
||||
TestResult::Offense o;
|
||||
o.offender = key + ".z";
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
res.offenses.push_back(o);
|
||||
}
|
||||
|
||||
return res;
|
||||
@@ -345,27 +372,39 @@ TestResult Color4Verifier::operator()(const ghoul::Dictionary& dictionary,
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<double> values = dictionary.value<std::vector<double>>(key);
|
||||
if (values[0] < 0.0 || values[0] > 1.0) {
|
||||
glm::dvec4 values = dictionary.value<glm::dvec4>(key);
|
||||
if (values.x < 0.0 || values.x > 1.0) {
|
||||
res.success = false;
|
||||
res.offenses.push_back({ key + ".x", TestResult::Offense::Reason::Verification });
|
||||
TestResult::Offense o;
|
||||
o.offender = key + ".x";
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
res.offenses.push_back(o);
|
||||
}
|
||||
|
||||
if (values[1] < 0.0 || values[1] > 1.0) {
|
||||
if (values.y < 0.0 || values.y > 1.0) {
|
||||
res.success = false;
|
||||
res.offenses.push_back({ key + ".y", TestResult::Offense::Reason::Verification });
|
||||
TestResult::Offense o;
|
||||
o.offender = key + ".y";
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
res.offenses.push_back(o);
|
||||
}
|
||||
|
||||
if (values[2] < 0.0 || values[2] > 1.0) {
|
||||
if (values.z < 0.0 || values.z > 1.0) {
|
||||
res.success = false;
|
||||
res.offenses.push_back({ key + ".z", TestResult::Offense::Reason::Verification });
|
||||
TestResult::Offense o;
|
||||
o.offender = key + ".z";
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
res.offenses.push_back(o);
|
||||
}
|
||||
|
||||
if (values[3] < 0.0 || values[3] > 1.0) {
|
||||
if (values.w < 0.0 || values.w > 1.0) {
|
||||
res.success = false;
|
||||
res.offenses.push_back({ key + ".a", TestResult::Offense::Reason::Verification });
|
||||
TestResult::Offense o;
|
||||
o.offender = key + ".a";
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
res.offenses.push_back(o);
|
||||
}
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -378,7 +417,9 @@ TestResult TemplateVerifier<glm::ivec2>::operator()(const ghoul::Dictionary& dic
|
||||
const std::string& key) const
|
||||
{
|
||||
if (dict.hasValue<glm::ivec2>(key)) {
|
||||
return { true, {}, {} };
|
||||
TestResult res;
|
||||
res.success = true;
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
if (dict.hasKey(key)) {
|
||||
@@ -390,22 +431,38 @@ TestResult TemplateVerifier<glm::ivec2>::operator()(const ghoul::Dictionary& dic
|
||||
modf(value.y, &intPart.y) == 0.0
|
||||
};
|
||||
if (isInt.x && isInt.y) {
|
||||
return { true, {}, {} };
|
||||
TestResult res;
|
||||
res.success = true;
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
return {
|
||||
false,
|
||||
{{ key, TestResult::Offense::Reason::WrongType }},
|
||||
{}
|
||||
};
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return { false, {{ key, TestResult::Offense::Reason::WrongType }}, {} };
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return { false, {{ key, TestResult::Offense::Reason::MissingKey }}, {} };
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::MissingKey;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -415,7 +472,9 @@ TestResult TemplateVerifier<glm::ivec3>::operator()(const ghoul::Dictionary& dic
|
||||
const std::string& key) const
|
||||
{
|
||||
if (dict.hasValue<glm::ivec3>(key)) {
|
||||
return { true, {}, {} };
|
||||
TestResult res;
|
||||
res.success = true;
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
if (dict.hasKey(key)) {
|
||||
@@ -428,22 +487,38 @@ TestResult TemplateVerifier<glm::ivec3>::operator()(const ghoul::Dictionary& dic
|
||||
modf(value.z, &intPart.z) == 0.0
|
||||
};
|
||||
if (isInt.x && isInt.y && isInt.z) {
|
||||
return { true, {}, {} };
|
||||
TestResult res;
|
||||
res.success = true;
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
return {
|
||||
false,
|
||||
{{ key, TestResult::Offense::Reason::WrongType }},
|
||||
{}
|
||||
};
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return { false, {{ key, TestResult::Offense::Reason::WrongType }}, {} };
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return { false, {{ key, TestResult::Offense::Reason::MissingKey }}, {} };
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::MissingKey;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -453,7 +528,9 @@ TestResult TemplateVerifier<glm::ivec4>::operator()(const ghoul::Dictionary& dic
|
||||
const std::string& key) const
|
||||
{
|
||||
if (dict.hasValue<glm::ivec4>(key)) {
|
||||
return { true, {}, {} };
|
||||
TestResult res;
|
||||
res.success = true;
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
if (dict.hasKey(key)) {
|
||||
@@ -467,22 +544,38 @@ TestResult TemplateVerifier<glm::ivec4>::operator()(const ghoul::Dictionary& dic
|
||||
modf(value.w, &intPart.w) == 0.0
|
||||
};
|
||||
if (isInt.x && isInt.y && isInt.z && isInt.w) {
|
||||
return { true, {}, {} };
|
||||
TestResult res;
|
||||
res.success = true;
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
return {
|
||||
false,
|
||||
{{ key, TestResult::Offense::Reason::WrongType }},
|
||||
{}
|
||||
};
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return { false, {{ key, TestResult::Offense::Reason::WrongType }}, {} };
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return { false, {{ key, TestResult::Offense::Reason::MissingKey }}, {} };
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::MissingKey;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -512,11 +605,22 @@ TestResult TableVerifier::operator()(const ghoul::Dictionary& dictionary,
|
||||
}
|
||||
else {
|
||||
if (dictionary.hasKey(key)) {
|
||||
return { false, { { key, TestResult::Offense::Reason::WrongType } }, {} };
|
||||
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::WrongType;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
return { false, { { key, TestResult::Offense::Reason::MissingKey } }, {} };
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::MissingKey;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -565,11 +669,11 @@ TestResult ReferencingVerifier::operator()(const ghoul::Dictionary& dictionary,
|
||||
);
|
||||
|
||||
if (it == docs.end()) {
|
||||
res.offenses.push_back({
|
||||
key,
|
||||
TestResult::Offense::Reason::UnknownIdentifier
|
||||
});
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::UnknownIdentifier;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -629,10 +733,18 @@ TestResult AndVerifier::operator()(const ghoul::Dictionary& dictionary,
|
||||
);
|
||||
|
||||
if (success) {
|
||||
return { true, {}, {} };
|
||||
TestResult res;
|
||||
res.success = true;
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
return { false, { { key, TestResult::Offense::Reason::Verification } }, {} };
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -698,10 +810,18 @@ TestResult OrVerifier::operator()(const ghoul::Dictionary& dictionary,
|
||||
);
|
||||
|
||||
if (success) {
|
||||
return { true, {}, {} };
|
||||
TestResult res;
|
||||
res.success = true;
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
return { false, { { key, TestResult::Offense::Reason::Verification } }, {} };
|
||||
TestResult res;
|
||||
res.success = false;
|
||||
TestResult::Offense o;
|
||||
o.offender = key;
|
||||
o.reason = TestResult::Offense::Reason::Verification;
|
||||
res.offenses.push_back(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace {
|
||||
std::optional<std::vector<std::string>> globalCustomizationScripts;
|
||||
|
||||
// A list of paths that are automatically registered with the file system. If a
|
||||
// key X is used in the table, it is then useable by referencing ${X} in all other
|
||||
// key X is used in the table, it is then useable by referencing ${X} in all other
|
||||
// configuration files or scripts
|
||||
std::map<std::string, std::string> paths;
|
||||
|
||||
@@ -277,7 +277,7 @@ namespace {
|
||||
// errors easier. This defaults to 'false'
|
||||
std::optional<bool> checkOpenGLState;
|
||||
|
||||
// Determines whether each OpenGL call that happens should be logged using the
|
||||
// Determines whether each OpenGL call that happens should be logged using the
|
||||
// 'TRACE' loglevel. This will bring the rendering to a crawl but provides useful
|
||||
// debugging features for the order in which OpenGL calls occur. This defaults to
|
||||
// 'false'
|
||||
@@ -312,7 +312,7 @@ namespace {
|
||||
// bar that gives an estimate of the loading progression
|
||||
std::optional<bool> showProgressbar;
|
||||
};
|
||||
// Values in this table describe the behavior of the loading screen that is
|
||||
// Values in this table describe the behavior of the loading screen that is
|
||||
// displayed while the scene graph is created and initialized
|
||||
std::optional<LoadingScreen> loadingScreen;
|
||||
|
||||
@@ -458,7 +458,7 @@ void parseLuaState(Configuration& configuration) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (p.documentation.has_value()) {
|
||||
c.documentation.path = p.documentation->path.value_or(c.documentation.path);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ void ModuleEngine::initialize(
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -306,11 +306,10 @@ int createSingleColorImage(lua_State* L) {
|
||||
|
||||
// @TODO (emmbr 2020-12-18) Verify that the input dictionary is a vec3
|
||||
// Would like to clean this up with a more direct use of the Verifier in the future
|
||||
using namespace openspace::documentation;
|
||||
const std::string& key = "color";
|
||||
ghoul::Dictionary colorDict;
|
||||
colorDict.setValue(key, d);
|
||||
TestResult res = Color3Verifier()(colorDict, key);
|
||||
documentation::TestResult res = documentation::Color3Verifier()(colorDict, key);
|
||||
|
||||
if (!res.success) {
|
||||
return ghoul::lua::luaError(
|
||||
|
||||
@@ -44,13 +44,6 @@
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "NavigationHandler";
|
||||
|
||||
constexpr const char* KeyAnchor = "Anchor";
|
||||
constexpr const char* KeyAim = "Aim";
|
||||
constexpr const char* KeyPosition = "Position";
|
||||
constexpr const char* KeyUp = "Up";
|
||||
constexpr const char* KeyYaw = "Yaw";
|
||||
constexpr const char* KeyPitch = "Pitch";
|
||||
constexpr const char* KeyReferenceFrame = "ReferenceFrame";
|
||||
const double Epsilon = 1E-7;
|
||||
|
||||
using namespace openspace;
|
||||
@@ -73,6 +66,31 @@ namespace {
|
||||
"than using the mouse interaction."
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(NavigationHandler)]] Parameters {
|
||||
// The identifier of the anchor node
|
||||
std::string anchor;
|
||||
|
||||
// The identifier of the aim node, if used
|
||||
std::optional<std::string> aim;
|
||||
|
||||
// The identifier of the scene graph node to use as reference frame. If not
|
||||
// specified, this will be the same as the anchor
|
||||
std::optional<std::string> referenceFrame;
|
||||
|
||||
// The position of the camera relative to the anchor node, expressed in meters in
|
||||
// the specified reference frame
|
||||
glm::dvec3 position;
|
||||
|
||||
// The up vector expressed in the coordinate system of the reference frame
|
||||
std::optional<glm::dvec3> up;
|
||||
|
||||
// The yaw angle in radians. Positive angle means yawing camera to the right
|
||||
std::optional<double> yaw;
|
||||
|
||||
// The pitch angle in radians. Positive angle means pitching camera upwards
|
||||
std::optional<double> pitch;
|
||||
};
|
||||
#include "navigationhandler_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
#include "navigationhandler_lua.inl"
|
||||
@@ -80,6 +98,14 @@ namespace {
|
||||
namespace openspace::interaction {
|
||||
|
||||
ghoul::Dictionary NavigationHandler::NavigationState::dictionary() const {
|
||||
constexpr const char* KeyAnchor = "Anchor";
|
||||
constexpr const char* KeyAim = "Aim";
|
||||
constexpr const char* KeyPosition = "Position";
|
||||
constexpr const char* KeyUp = "Up";
|
||||
constexpr const char* KeyYaw = "Yaw";
|
||||
constexpr const char* KeyPitch = "Pitch";
|
||||
constexpr const char* KeyReferenceFrame = "ReferenceFrame";
|
||||
|
||||
ghoul::Dictionary cameraDict;
|
||||
cameraDict.setValue(KeyPosition, position);
|
||||
cameraDict.setValue(KeyAnchor, anchor);
|
||||
@@ -105,36 +131,19 @@ ghoul::Dictionary NavigationHandler::NavigationState::dictionary() const {
|
||||
}
|
||||
|
||||
NavigationHandler::NavigationState::NavigationState(const ghoul::Dictionary& dictionary) {
|
||||
const bool hasAnchor = dictionary.hasValue<std::string>(KeyAnchor);
|
||||
const bool hasPosition = dictionary.hasValue<glm::dvec3>(KeyPosition);
|
||||
if (!hasAnchor || !hasPosition) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Position and Anchor need to be defined for navigation dictionary."
|
||||
);
|
||||
}
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
anchor = dictionary.value<std::string>(KeyAnchor);
|
||||
position = dictionary.value<glm::dvec3>(KeyPosition);
|
||||
anchor = p.anchor;
|
||||
position = p.position;
|
||||
|
||||
if (dictionary.hasValue<std::string>(KeyReferenceFrame)) {
|
||||
referenceFrame = dictionary.value<std::string>(KeyReferenceFrame);
|
||||
}
|
||||
else {
|
||||
referenceFrame = anchor;
|
||||
}
|
||||
if (dictionary.hasValue<std::string>(KeyAim)) {
|
||||
aim = dictionary.value<std::string>(KeyAim);
|
||||
}
|
||||
referenceFrame = p.referenceFrame.value_or(anchor);
|
||||
aim = p.aim.value_or(aim);
|
||||
|
||||
if (dictionary.hasValue<glm::dvec3>(KeyUp)) {
|
||||
up = dictionary.value<glm::dvec3>(KeyUp);
|
||||
if (p.up.has_value()) {
|
||||
up = *p.up;
|
||||
|
||||
if (dictionary.hasValue<double>(KeyYaw)) {
|
||||
yaw = dictionary.value<double>(KeyYaw);
|
||||
}
|
||||
if (dictionary.hasValue<double>(KeyPitch)) {
|
||||
pitch = dictionary.value<double>(KeyPitch);
|
||||
}
|
||||
yaw = p.yaw.value_or(yaw);
|
||||
pitch = p.pitch.value_or(pitch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,8 +151,7 @@ NavigationHandler::NavigationState::NavigationState(std::string anchor_, std::st
|
||||
std::string referenceFrame_,
|
||||
glm::dvec3 position_,
|
||||
std::optional<glm::dvec3> up_,
|
||||
double yaw_,
|
||||
double pitch_)
|
||||
double yaw_, double pitch_)
|
||||
: anchor(std::move(anchor_))
|
||||
, aim(std::move(aim_))
|
||||
, referenceFrame(std::move(referenceFrame_))
|
||||
@@ -545,60 +553,9 @@ std::vector<std::string> NavigationHandler::joystickButtonCommand(int button) co
|
||||
}
|
||||
|
||||
documentation::Documentation NavigationHandler::NavigationState::Documentation() {
|
||||
using namespace documentation;
|
||||
|
||||
return {
|
||||
"Navigation State",
|
||||
"core_navigation_state",
|
||||
{
|
||||
{
|
||||
KeyAnchor,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The identifier of the anchor node."
|
||||
},
|
||||
{
|
||||
KeyAim,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"The identifier of the aim node, if used."
|
||||
},
|
||||
{
|
||||
KeyReferenceFrame,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"The identifier of the scene graph node to use as reference frame. "
|
||||
"If not specified, this will be the same as the anchor."
|
||||
},
|
||||
{
|
||||
KeyPosition,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::No,
|
||||
"The position of the camera relative to the anchor node, "
|
||||
"expressed in meters in the specified reference frame."
|
||||
},
|
||||
{
|
||||
KeyUp,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::Yes,
|
||||
"The up vector expressed in the coordinate system of the reference frame."
|
||||
},
|
||||
{
|
||||
KeyYaw,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"The yaw angle in radians. "
|
||||
"Positive angle means yawing camera to the right."
|
||||
},
|
||||
{
|
||||
KeyPitch,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"The pitch angle in radians. "
|
||||
"Positive angle means pitching camera upwards."
|
||||
},
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "core_navigation_state";
|
||||
return doc;
|
||||
}
|
||||
|
||||
scripting::LuaLibrary NavigationHandler::luaLibrary() {
|
||||
|
||||
@@ -29,73 +29,47 @@
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/lua/lua_helper.h>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyName = "Name";
|
||||
constexpr const char* KeyDescription = "Description";
|
||||
constexpr const char* KeyPhases = "Phases";
|
||||
constexpr const char* KeyTimeRange = "TimeRange";
|
||||
struct [[codegen::Dictionary(MissionPhase)]] Parameters {
|
||||
// The human readable name of this mission or mission phase that is displayed to
|
||||
// the user
|
||||
std::string name;
|
||||
|
||||
// A description of this mission or mission phase
|
||||
std::optional<std::string> description;
|
||||
|
||||
// The time range for which this mission or mission phase is valid. If no time
|
||||
// range is specified, the ranges of sub mission phases are used instead
|
||||
std::optional<ghoul::Dictionary> timeRange
|
||||
[[codegen::reference("core_util_timerange")]];
|
||||
|
||||
// The phases into which this mission or mission phase is separated
|
||||
std::optional<std::vector<ghoul::Dictionary>> phases
|
||||
[[codegen::reference("core_mission_mission")]];
|
||||
};
|
||||
#include "mission_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation MissionPhase::Documentation() {
|
||||
using namespace documentation;
|
||||
|
||||
return {
|
||||
"Missions and Mission Phases",
|
||||
"core_mission_mission",
|
||||
{
|
||||
{
|
||||
KeyName,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The human readable name of this mission or mission phase that is "
|
||||
"displayed to the user."
|
||||
},
|
||||
{
|
||||
KeyDescription,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"A description of this mission or mission phase."
|
||||
},
|
||||
{
|
||||
KeyTimeRange,
|
||||
new ReferencingVerifier("core_util_timerange"),
|
||||
Optional::Yes,
|
||||
"The time range for which this mission or mission phase is valid. If no "
|
||||
"time range is specified, the ranges of sub mission phases are used "
|
||||
"instead."
|
||||
},
|
||||
{
|
||||
KeyPhases,
|
||||
new TableVerifier({
|
||||
{
|
||||
"*",
|
||||
new ReferencingVerifier("core_mission_mission"),
|
||||
Optional::Yes
|
||||
}
|
||||
}),
|
||||
Optional::Yes,
|
||||
"The phases into which this mission or mission phase is separated."
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "core_mission_mission";
|
||||
return doc;
|
||||
}
|
||||
|
||||
MissionPhase::MissionPhase(const ghoul::Dictionary& dictionary) {
|
||||
_name = dictionary.value<std::string>(KeyName);
|
||||
if (dictionary.hasValue<std::string>(KeyDescription)) {
|
||||
_description = dictionary.value<std::string>(KeyDescription);
|
||||
}
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
if (dictionary.hasValue<ghoul::Dictionary>(KeyPhases)) {
|
||||
ghoul::Dictionary childDicts = dictionary.value<ghoul::Dictionary>(KeyPhases);
|
||||
// This is a nested mission phase
|
||||
_subphases.reserve(childDicts.size());
|
||||
for (size_t i = 0; i < childDicts.size(); ++i) {
|
||||
std::string key = std::to_string(i + 1);
|
||||
_subphases.emplace_back(childDicts.value<ghoul::Dictionary>(key));
|
||||
_name = p.name;
|
||||
_description = p.description.value_or(_description);
|
||||
|
||||
if (p.phases.has_value()) {
|
||||
_subphases.reserve(p.phases->size());
|
||||
for (const ghoul::Dictionary& phase : *p.phases) {
|
||||
_subphases.emplace_back(phase);
|
||||
}
|
||||
|
||||
// Ensure subphases are sorted
|
||||
@@ -112,15 +86,14 @@ MissionPhase::MissionPhase(const ghoul::Dictionary& dictionary) {
|
||||
timeRangeSubPhases.start = _subphases[0].timeRange().start;
|
||||
timeRangeSubPhases.end = _subphases.back().timeRange().end;
|
||||
|
||||
// user may specify an overall time range. In that case expand this timerange.
|
||||
if (dictionary.hasValue<ghoul::Dictionary>(KeyTimeRange)) {
|
||||
ghoul::Dictionary range = dictionary.value<ghoul::Dictionary>(KeyTimeRange);
|
||||
TimeRange overallTimeRange(range);
|
||||
// user may specify an overall time range. In that case expand this timerange
|
||||
if (p.timeRange.has_value()) {
|
||||
TimeRange overallTimeRange(*p.timeRange);
|
||||
if (!overallTimeRange.includes(timeRangeSubPhases)) {
|
||||
throw ghoul::RuntimeError(
|
||||
throw ghoul::RuntimeError(fmt::format(
|
||||
"User specified time range must at least include its subphases'",
|
||||
"Mission (" + _name + ")"
|
||||
);
|
||||
"Mission ({})", _name
|
||||
));
|
||||
}
|
||||
|
||||
_timeRange.include(overallTimeRange);
|
||||
@@ -132,16 +105,14 @@ MissionPhase::MissionPhase(const ghoul::Dictionary& dictionary) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (dictionary.hasValue<ghoul::Dictionary>(KeyTimeRange)) {
|
||||
ghoul::Dictionary timeRangeDict =
|
||||
dictionary.value<ghoul::Dictionary>(KeyTimeRange);
|
||||
_timeRange = TimeRange(timeRangeDict); // throws exception if unable to parse
|
||||
if (p.timeRange.has_value()) {
|
||||
_timeRange = TimeRange(*p.timeRange); // throws exception if unable to parse
|
||||
}
|
||||
else {
|
||||
throw ghoul::RuntimeError(
|
||||
throw ghoul::RuntimeError(fmt::format(
|
||||
"If there are no subphases specified, the time range has to be specified",
|
||||
"Mission (" + _name + ")"
|
||||
);
|
||||
"Mission ({})", _name
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ DashboardItem::DashboardItem(const ghoul::Dictionary& dictionary)
|
||||
, _isEnabled(EnabledInfo, true)
|
||||
{
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
|
||||
setIdentifier(p.identifier);
|
||||
if (p.guiName.has_value()) {
|
||||
setGuiName(*p.guiName);
|
||||
|
||||
@@ -129,7 +129,7 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary)
|
||||
registerUpdateRenderBinFromOpacity();
|
||||
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
|
||||
if (p.tag.has_value()) {
|
||||
if (std::holds_alternative<std::string>(*p.tag)) {
|
||||
if (!std::get<std::string>(*p.tag).empty()) {
|
||||
|
||||
@@ -38,11 +38,10 @@
|
||||
#include <ghoul/misc/profiling.h>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <ghoul/opengl/textureunit.h>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyType = "Type";
|
||||
constexpr const char* KeyTag = "Tag";
|
||||
|
||||
constexpr const std::array<const char*, 4> UniformNames = {
|
||||
"Alpha", "ModelTransform", "ViewProjectionMatrix", "texture1"
|
||||
};
|
||||
@@ -207,109 +206,72 @@ namespace {
|
||||
wrap(elevation, -glm::pi<float>(), glm::pi<float>())
|
||||
);
|
||||
}
|
||||
|
||||
struct [[codegen::Dictionary(ScreenSpaceRenderable)]] Parameters {
|
||||
// The type of the Screenspace renderable that is to be created. The available
|
||||
// types of Screenspace renderable depend on the configuration of the application
|
||||
// and can be written to disk on application startup into the FactoryDocumentation
|
||||
std::string type
|
||||
[[codegen::annotation("Must name a valid Screenspace renderable")]];
|
||||
|
||||
// Specifies the name of this screenspace renderable. This does not have to be
|
||||
// unique to the scene, but it is recommended to be
|
||||
std::optional<std::string> name;
|
||||
|
||||
// This is the unique identifier for this screenspace renderable. It has to be
|
||||
// unique amongst all existing screenspace nodes that already have been added to
|
||||
// the scene. The identifier is not allowed to have any whitespace or '.' and must
|
||||
// not be empty
|
||||
std::optional<std::string> identifier;
|
||||
|
||||
// [[codegen::verbatim(EnabledInfo.description)]]
|
||||
std::optional<bool> enabled;
|
||||
|
||||
// [[codegen::verbatim(UseRadiusAzimuthElevationInfo.description)]]
|
||||
std::optional<bool> useRadiusAzimuthElevation;
|
||||
|
||||
// [[codegen::verbatim(FaceCameraInfo.description)]]
|
||||
std::optional<bool> faceCamera;
|
||||
|
||||
// [[codegen::verbatim(CartesianPositionInfo.description)]]
|
||||
std::optional<glm::vec3> cartesianPosition;
|
||||
|
||||
// [[codegen::verbatim(RadiusAzimuthElevationInfo.description)]]
|
||||
std::optional<glm::vec3> radiusAzimuthElevation;
|
||||
|
||||
// [[codegen::verbatim(ScaleInfo.description)]]
|
||||
std::optional<float> scale;
|
||||
|
||||
// [[codegen::verbatim(UsePerspectiveProjectionInfo.description)]]
|
||||
std::optional<bool> usePerspectiveProjection;
|
||||
|
||||
// [codegen::verbatim(OpacityInfo.description)]]
|
||||
std::optional<float> opacity [[codegen::inrange(0.f, 1.f)]];
|
||||
|
||||
// Defines either a single or multiple tags that apply to this
|
||||
// ScreenSpaceRenderable, thus making it possible to address multiple, separate
|
||||
// Renderables with a single property change
|
||||
std::optional<std::variant<std::string, std::vector<std::string>>> tag;
|
||||
};
|
||||
#include "screenspacerenderable_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation ScreenSpaceRenderable::Documentation() {
|
||||
using namespace openspace::documentation;
|
||||
|
||||
return {
|
||||
"Screenspace Renderable",
|
||||
"core_screenspacerenderable",
|
||||
{
|
||||
{
|
||||
KeyType,
|
||||
new StringAnnotationVerifier("Must name a valid Screenspace renderable"),
|
||||
Optional::No,
|
||||
"The type of the Screenspace renderable that is to be created. The "
|
||||
"available types of Screenspace renderable depend on the configuration of"
|
||||
"the application and can be written to disk on application startup into "
|
||||
"the FactoryDocumentation."
|
||||
},
|
||||
{
|
||||
KeyName,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies the name of this screenspace renderable. This does not have "
|
||||
"to be unique to the scene, but it is recommended to be."
|
||||
},
|
||||
{
|
||||
KeyIdentifier,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"This is the unique identifier for this screenspace renderable. It has "
|
||||
"to be unique amongst all existing screenspace nodes that already have "
|
||||
"been added to the scene. The identifier is not allowed to have any "
|
||||
"whitespace or '.' and must not be empty."
|
||||
},
|
||||
{
|
||||
EnabledInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
EnabledInfo.description
|
||||
},
|
||||
{
|
||||
UseRadiusAzimuthElevationInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
UseRadiusAzimuthElevationInfo.description
|
||||
},
|
||||
{
|
||||
FaceCameraInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
FaceCameraInfo.description
|
||||
},
|
||||
{
|
||||
CartesianPositionInfo.identifier,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::Yes,
|
||||
CartesianPositionInfo.description
|
||||
},
|
||||
{
|
||||
RadiusAzimuthElevationInfo.identifier,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::Yes,
|
||||
RadiusAzimuthElevationInfo.description
|
||||
},
|
||||
{
|
||||
ScaleInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
ScaleInfo.description
|
||||
},
|
||||
{
|
||||
OpacityInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
OpacityInfo.description
|
||||
},
|
||||
{
|
||||
KeyTag,
|
||||
new OrVerifier({ new StringVerifier, new StringListVerifier }),
|
||||
Optional::Yes,
|
||||
"Defines either a single or multiple tags that apply to this "
|
||||
"ScreenSpaceRenderable, thus making it possible to address multiple, "
|
||||
"seprate Renderables with a single property change."
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "core_screenspacerenderable";
|
||||
return doc;
|
||||
}
|
||||
|
||||
std::unique_ptr<ScreenSpaceRenderable> ScreenSpaceRenderable::createFromDictionary(
|
||||
const ghoul::Dictionary& dictionary)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"ScreenSpaceRenderable"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
const std::string& renderableType = dictionary.value<std::string>(KeyType);
|
||||
ScreenSpaceRenderable* ssr =
|
||||
FactoryManager::ref().factory<ScreenSpaceRenderable>()->create(
|
||||
renderableType,
|
||||
p.type,
|
||||
dictionary
|
||||
);
|
||||
return std::unique_ptr<ScreenSpaceRenderable>(ssr);
|
||||
@@ -365,12 +327,14 @@ ScreenSpaceRenderable::ScreenSpaceRenderable(const ghoul::Dictionary& dictionary
|
||||
, _opacity(OpacityInfo, 1.f, 0.f, 1.f)
|
||||
, _delete(DeleteInfo)
|
||||
{
|
||||
if (dictionary.hasKey(KeyIdentifier)) {
|
||||
setIdentifier(dictionary.value<std::string>(KeyIdentifier));
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
if (p.identifier.has_value()) {
|
||||
setIdentifier(*p.identifier);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyName)) {
|
||||
setGuiName(dictionary.value<std::string>(KeyName));
|
||||
if (p.name.has_value()) {
|
||||
setGuiName(*p.name);
|
||||
}
|
||||
|
||||
addProperty(_enabled);
|
||||
@@ -394,62 +358,38 @@ ScreenSpaceRenderable::ScreenSpaceRenderable(const ghoul::Dictionary& dictionary
|
||||
addProperty(_opacity);
|
||||
addProperty(_localRotation);
|
||||
|
||||
if (dictionary.hasKey(EnabledInfo.identifier)) {
|
||||
_enabled = dictionary.value<bool>(EnabledInfo.identifier);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(UseRadiusAzimuthElevationInfo.identifier)) {
|
||||
_useRadiusAzimuthElevation = dictionary.value<bool>(
|
||||
UseRadiusAzimuthElevationInfo.identifier
|
||||
);
|
||||
}
|
||||
_enabled = p.enabled.value_or(_enabled);
|
||||
_useRadiusAzimuthElevation =
|
||||
p.useRadiusAzimuthElevation.value_or(_useRadiusAzimuthElevation);
|
||||
|
||||
if (_useRadiusAzimuthElevation) {
|
||||
if (dictionary.hasKey(RadiusAzimuthElevationInfo.identifier)) {
|
||||
_raePosition = dictionary.value<glm::dvec3>(
|
||||
RadiusAzimuthElevationInfo.identifier
|
||||
);
|
||||
}
|
||||
_raePosition = p.radiusAzimuthElevation.value_or(_raePosition);
|
||||
}
|
||||
else {
|
||||
if (dictionary.hasKey(CartesianPositionInfo.identifier)) {
|
||||
_cartesianPosition = dictionary.value<glm::dvec3>(
|
||||
CartesianPositionInfo.identifier
|
||||
);
|
||||
_cartesianPosition = p.cartesianPosition.value_or(_cartesianPosition);
|
||||
}
|
||||
|
||||
_scale = p.scale.value_or(_scale);
|
||||
_opacity = p.opacity.value_or(_opacity);
|
||||
_usePerspectiveProjection =
|
||||
p.usePerspectiveProjection.value_or(_usePerspectiveProjection);
|
||||
|
||||
_faceCamera = p.faceCamera.value_or(_faceCamera);
|
||||
|
||||
if (p.tag.has_value()) {
|
||||
if (std::holds_alternative<std::string>(*p.tag)) {
|
||||
addTag(std::get<std::string>(*p.tag));
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(ScaleInfo.identifier)) {
|
||||
_scale = static_cast<float>(dictionary.value<double>(ScaleInfo.identifier));
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(OpacityInfo.identifier)) {
|
||||
_opacity = static_cast<float>(dictionary.value<double>(OpacityInfo.identifier));
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(UsePerspectiveProjectionInfo.identifier)) {
|
||||
_usePerspectiveProjection =
|
||||
dictionary.value<bool>(UsePerspectiveProjectionInfo.identifier);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(FaceCameraInfo.identifier)) {
|
||||
_faceCamera = dictionary.value<bool>(FaceCameraInfo.identifier);
|
||||
}
|
||||
|
||||
if (dictionary.hasValue<std::string>(KeyTag)) {
|
||||
std::string tagName = dictionary.value<std::string>(KeyTag);
|
||||
if (!tagName.empty()) {
|
||||
addTag(std::move(tagName));
|
||||
}
|
||||
}
|
||||
else if (dictionary.hasValue<ghoul::Dictionary>(KeyTag)) {
|
||||
const ghoul::Dictionary& tagNames = dictionary.value<ghoul::Dictionary>(KeyTag);
|
||||
for (std::string_view key : tagNames.keys()) {
|
||||
std::string tagName = tagNames.value<std::string>(key);
|
||||
if (!tagName.empty()) {
|
||||
addTag(std::move(tagName));
|
||||
else if (std::holds_alternative<std::vector<std::string>>(*p.tag)) {
|
||||
for (const std::string& t : std::get<std::vector<std::string>>(*p.tag)) {
|
||||
if (!t.empty()) {
|
||||
addTag(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}
|
||||
|
||||
_delete.onChange([this](){
|
||||
|
||||
@@ -32,17 +32,28 @@
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
#include <ghoul/misc/templatefactory.h>
|
||||
#include <optional>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyType = "Type";
|
||||
|
||||
constexpr const char* KeyIdentifier = "Identifier";
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo EnabledInfo = {
|
||||
"Enabled",
|
||||
"Enabled",
|
||||
"Whether the light source is enabled or not"
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(LightSource)]] Parameters {
|
||||
// The type of the light source that is described in this element. The available
|
||||
// types of light sources depend on the configuration of the application and can
|
||||
// be written to disk on application startup into the FactoryDocumentation
|
||||
std::string type [[codegen::annotation("Must name a valid LightSource type")]];
|
||||
|
||||
// The identifier of the light source
|
||||
std::string identifier;
|
||||
|
||||
// [[codegen::verbatim(EnabledInfo.description)]]
|
||||
std::optional<bool> enabled;
|
||||
};
|
||||
#include "lightsource_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
@@ -52,49 +63,19 @@ bool LightSource::isEnabled() const {
|
||||
}
|
||||
|
||||
documentation::Documentation LightSource::Documentation() {
|
||||
using namespace openspace::documentation;
|
||||
|
||||
return {
|
||||
"Light Source",
|
||||
"core_light_source",
|
||||
{
|
||||
{
|
||||
KeyType,
|
||||
new StringAnnotationVerifier("Must name a valid LightSource type"),
|
||||
Optional::No,
|
||||
"The type of the light source that is described in this element. "
|
||||
"The available types of light sources depend on the configuration "
|
||||
"of the application and can be written to disk on "
|
||||
"application startup into the FactoryDocumentation."
|
||||
},
|
||||
{
|
||||
KeyIdentifier,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The identifier of the light source."
|
||||
},
|
||||
{
|
||||
EnabledInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
EnabledInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "core_light_source";
|
||||
return doc;
|
||||
}
|
||||
|
||||
std::unique_ptr<LightSource> LightSource::createFromDictionary(
|
||||
const ghoul::Dictionary& dictionary)
|
||||
const ghoul::Dictionary& dictionary)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(Documentation(), dictionary, "LightSource");
|
||||
|
||||
const std::string timeFrameType = dictionary.value<std::string>(KeyType);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
auto factory = FactoryManager::ref().factory<LightSource>();
|
||||
LightSource* source = factory->create(timeFrameType, dictionary);
|
||||
|
||||
const std::string identifier = dictionary.value<std::string>(KeyIdentifier);
|
||||
source->setIdentifier(identifier);
|
||||
LightSource* source = factory->create(p.type, dictionary);
|
||||
source->setIdentifier(p.identifier);
|
||||
|
||||
return std::unique_ptr<LightSource>(source);
|
||||
}
|
||||
@@ -110,10 +91,9 @@ LightSource::LightSource(const ghoul::Dictionary& dictionary)
|
||||
: properties::PropertyOwner({ "LightSource" })
|
||||
, _enabled(EnabledInfo, true)
|
||||
{
|
||||
if (dictionary.hasValue<bool>(EnabledInfo.identifier)) {
|
||||
_enabled = dictionary.value<bool>(EnabledInfo.identifier);
|
||||
}
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_enabled = p.enabled.value_or(_enabled);
|
||||
addProperty(_enabled);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,40 +36,30 @@
|
||||
#include <ghoul/misc/templatefactory.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyType = "Type";
|
||||
struct [[codegen::Dictionary(Rotation)]] Parameters {
|
||||
// The type of the rotation that is described in this element. The available types
|
||||
// of rotations depend on the configuration of the application and can be written
|
||||
// to disk on application startup into the FactoryDocumentation
|
||||
std::string type [[codegen::annotation("Must name a valid Rotation type")]];
|
||||
};
|
||||
#include "rotation_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation Rotation::Documentation() {
|
||||
using namespace openspace::documentation;
|
||||
|
||||
return {
|
||||
"Transformation Rotation",
|
||||
"core_transform_rotation",
|
||||
{
|
||||
{
|
||||
KeyType,
|
||||
new StringAnnotationVerifier("Must name a valid Rotation type."),
|
||||
Optional::No,
|
||||
"The type of the rotation that is described in this element. The "
|
||||
"available types of rotations depend on the configuration of the "
|
||||
"application and can be written to disk on application startup into the "
|
||||
"FactoryDocumentation."
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "core_transform_rotation";
|
||||
return doc;
|
||||
}
|
||||
|
||||
ghoul::mm_unique_ptr<Rotation> Rotation::createFromDictionary(
|
||||
const ghoul::Dictionary& dictionary)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(Documentation(), dictionary, "Rotation");
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
const std::string& rotationType = dictionary.value<std::string>(KeyType);
|
||||
auto factory = FactoryManager::ref().factory<Rotation>();
|
||||
Rotation* result = factory->create(
|
||||
rotationType,
|
||||
Rotation* result = FactoryManager::ref().factory<Rotation>()->create(
|
||||
p.type,
|
||||
dictionary,
|
||||
&global::memoryManager->PersistentMemory
|
||||
);
|
||||
@@ -78,6 +68,8 @@ ghoul::mm_unique_ptr<Rotation> Rotation::createFromDictionary(
|
||||
|
||||
Rotation::Rotation() : properties::PropertyOwner({ "Rotation" }) {}
|
||||
|
||||
// @TODO (abock, 2021-03-25) This constructor can probably die since it doesn't do any
|
||||
// above the default constructor
|
||||
Rotation::Rotation(const ghoul::Dictionary&)
|
||||
: properties::PropertyOwner({ "Rotation" })
|
||||
{}
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include <modules/base/scale/staticscale.h>
|
||||
#include <modules/base/rotation/staticrotation.h>
|
||||
#include <modules/base/translation/statictranslation.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
@@ -38,23 +40,11 @@
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <ghoul/misc/profiling.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include "scenegraphnode_doc.inl"
|
||||
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "SceneGraphNode";
|
||||
constexpr const char* KeyRenderable = "Renderable";
|
||||
constexpr const char* KeyGuiName = "GUI.Name";
|
||||
constexpr const char* KeyGuiPath = "GUI.Path";
|
||||
constexpr const char* KeyGuiHidden = "GUI.Hidden";
|
||||
constexpr const char* KeyGuiDescription = "GUI.Description";
|
||||
|
||||
constexpr const char* KeyTransformTranslation = "Transform.Translation";
|
||||
constexpr const char* KeyTransformRotation = "Transform.Rotation";
|
||||
constexpr const char* KeyTransformScale = "Transform.Scale";
|
||||
|
||||
constexpr const char* KeyTimeFrame = "TimeFrame";
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ComputeScreenSpaceInfo =
|
||||
{
|
||||
@@ -138,6 +128,90 @@ namespace {
|
||||
openspace::properties::Property::Visibility::Hidden
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(SceneGraphNode)]] Parameters {
|
||||
// The identifier of this scenegraph node. This name must be unique among all
|
||||
// scene graph nodes that are loaded in a specific scene. If a duplicate is
|
||||
// detected the loading of the node will fail, as will all childing that depend on
|
||||
// the node. The identifier must not contain any whitespaces or '.'
|
||||
std::string identifier;
|
||||
|
||||
// This names the parent of the currently specified scenegraph node. The parent
|
||||
// must already exist in the scene graph. If not specified, the node will be
|
||||
// attached to the root of the scenegraph
|
||||
std::optional<std::string> parent
|
||||
[[codegen::annotation(
|
||||
"If specified, this must be a name for another scenegraph node"
|
||||
)]];
|
||||
|
||||
// The renderable that is to be created for this scenegraph node. A renderable is
|
||||
// a component of a scenegraph node that will lead to some visual result on the
|
||||
// screen. The specifics heavily depend on the 'Type' of the renderable. If no
|
||||
// Renderable is specified, this scenegraph node is an internal node and can be
|
||||
// used for either group children, or apply common transformations to a group of
|
||||
// children
|
||||
std::optional<ghoul::Dictionary> renderable [[codegen::reference("renderable")]];
|
||||
|
||||
// A hard-coded bounding sphere to be used for the cases where the Renderable is
|
||||
// not able to provide a reasonable bounding sphere or the calculated bounding
|
||||
// sphere needs to be overwritten for some reason
|
||||
std::optional<double> boundingSphere;
|
||||
|
||||
struct Transform {
|
||||
// This node describes a translation that is applied to the scenegraph node
|
||||
// and all its children. Depending on the 'Type' of the translation, this can
|
||||
// either be a static translation or a time-varying one
|
||||
std::optional<ghoul::Dictionary> translation
|
||||
[[codegen::reference("core_transform_translation")]];
|
||||
|
||||
// This nodes describes a rotation that is applied to the scenegraph node and
|
||||
// all its children. Depending on the 'Type' of the rotation, this can either
|
||||
// be a static rotation or a time-varying one
|
||||
std::optional<ghoul::Dictionary> rotation
|
||||
[[codegen::reference("core_transform_rotation")]];
|
||||
|
||||
// This node describes a scaling that is applied to the scenegraph node and
|
||||
// all its children. Depending on the 'Type' of the scaling, this can either
|
||||
// be a static scaling or a time-varying one
|
||||
std::optional<ghoul::Dictionary> scale
|
||||
[[codegen::reference("core_transform_scaling")]];
|
||||
};
|
||||
|
||||
// This describes a set of transformations that are applied to this scenegraph
|
||||
// node and all of its children. There are only three possible values
|
||||
// corresponding to a 'Translation', a 'Rotation', and a 'Scale'
|
||||
std::optional<Transform> transform;
|
||||
|
||||
// Specifies the time frame for when this node should be active
|
||||
std::optional<ghoul::Dictionary> timeFrame
|
||||
[[codegen::reference("core_time_frame")]];
|
||||
|
||||
// A tag or list of tags that can be used to reference to a group of scenegraph
|
||||
// nodes.
|
||||
std::optional<std::variant<std::string, std::vector<std::string>>> tag;
|
||||
|
||||
struct Gui {
|
||||
// An optional user-facing name for this SceneGraphNode, which does not have
|
||||
// to be unique, though it is recommended, and can contain any characters
|
||||
std::optional<std::string> name;
|
||||
|
||||
// If this value is specified, this '/' separated URI specifies the location
|
||||
// of this scenegraph node in a GUI representation, for instance
|
||||
// '/SolarSystem/Earth/Moon'
|
||||
std::optional<std::string> path;
|
||||
|
||||
// A user-facing description about this scene graph node
|
||||
std::optional<std::string> description;
|
||||
|
||||
// If this value is specified, GUI applications are incouraged to ignore this
|
||||
// scenegraph node. This is most useful to trim collective lists of nodes and
|
||||
// not display, for example, barycenters
|
||||
std::optional<bool> hidden;
|
||||
};
|
||||
// Additional information that is passed to GUI applications. These are all hints
|
||||
// and do not have any impact on the actual function of the scenegraph node
|
||||
std::optional<Gui> gui [[codegen::key("GUI")]];
|
||||
};
|
||||
#include "scenegraphnode_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
@@ -149,11 +223,7 @@ int SceneGraphNode::nextIndex = 0;
|
||||
ghoul::mm_unique_ptr<SceneGraphNode> SceneGraphNode::createFromDictionary(
|
||||
const ghoul::Dictionary& dictionary)
|
||||
{
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
SceneGraphNode::Documentation(),
|
||||
dictionary,
|
||||
"SceneGraphNode"
|
||||
);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
SceneGraphNode* n = global::memoryManager->PersistentMemory.alloc<SceneGraphNode>();
|
||||
ghoul::mm_unique_ptr<SceneGraphNode> result = ghoul::mm_unique_ptr<SceneGraphNode>(n);
|
||||
@@ -162,89 +232,102 @@ ghoul::mm_unique_ptr<SceneGraphNode> SceneGraphNode::createFromDictionary(
|
||||
result->index = nextIndex++;
|
||||
#endif // Debugging_Core_SceneGraphNode_Indices
|
||||
|
||||
std::string identifier = dictionary.value<std::string>(KeyIdentifier);
|
||||
result->setIdentifier(std::move(identifier));
|
||||
result->setIdentifier(p.identifier);
|
||||
|
||||
if (dictionary.hasKey(KeyGuiName)) {
|
||||
result->setGuiName(dictionary.value<std::string>(KeyGuiName));
|
||||
result->_guiDisplayName = result->guiName();
|
||||
result->addProperty(result->_guiDisplayName);
|
||||
if (p.gui.has_value()) {
|
||||
if (p.gui->name.has_value()) {
|
||||
result->setGuiName(*p.gui->name);
|
||||
result->_guiDisplayName = result->guiName();
|
||||
result->addProperty(result->_guiDisplayName);
|
||||
}
|
||||
|
||||
if (p.gui->description.has_value()) {
|
||||
result->setDescription(*p.gui->description);
|
||||
result->_guiDescription = result->description();
|
||||
result->addProperty(result->_guiDescription);
|
||||
}
|
||||
|
||||
if (p.gui->hidden.has_value()) {
|
||||
result->_guiHidden = *p.gui->hidden;
|
||||
result->addProperty(result->_guiHidden);
|
||||
}
|
||||
|
||||
if (p.gui->path.has_value()) {
|
||||
result->_guiPath = *p.gui->path;
|
||||
result->addProperty(result->_guiPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyGuiDescription)) {
|
||||
result->setDescription(dictionary.value<std::string>(KeyGuiDescription));
|
||||
result->_guiDescription = result->description();
|
||||
result->addProperty(result->_guiDescription);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyGuiHidden)) {
|
||||
result->_guiHidden = dictionary.value<bool>(KeyGuiHidden);
|
||||
result->addProperty(result->_guiHidden);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(BoundingSphereInfo.identifier)) {
|
||||
result->_boundingSphere = dictionary.value<double>(BoundingSphereInfo.identifier);
|
||||
if (p.boundingSphere.has_value()) {
|
||||
result->_boundingSphere = *p.boundingSphere;
|
||||
result->_boundingSphere.setVisibility(properties::Property::Visibility::All);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyTransformTranslation)) {
|
||||
ghoul::Dictionary translationDictionary =
|
||||
dictionary.value<ghoul::Dictionary>(KeyTransformTranslation);
|
||||
result->_transform.translation = Translation::createFromDictionary(
|
||||
translationDictionary
|
||||
);
|
||||
if (result->_transform.translation == nullptr) {
|
||||
LERROR(fmt::format(
|
||||
"Failed to create ephemeris for SceneGraphNode '{}'", result->identifier()
|
||||
if (p.transform.has_value()) {
|
||||
if (p.transform->translation.has_value()) {
|
||||
result->_transform.translation = Translation::createFromDictionary(
|
||||
*p.transform->translation
|
||||
);
|
||||
|
||||
// @TODO(abock, 2021-03-05) I don't think this is necessary anymore as we
|
||||
// transitioned to throwing exceptions when the construction fails
|
||||
if (result->_transform.translation == nullptr) {
|
||||
LERROR(fmt::format(
|
||||
"Failed to create ephemeris for SceneGraphNode '{}'",
|
||||
result->identifier()
|
||||
));
|
||||
return nullptr;
|
||||
}
|
||||
LDEBUG(fmt::format(
|
||||
"Successfully created ephemeris for '{}'", result->identifier()
|
||||
));
|
||||
return nullptr;
|
||||
result->addPropertySubOwner(result->_transform.translation.get());
|
||||
}
|
||||
|
||||
if (p.transform->rotation.has_value()) {
|
||||
result->_transform.rotation = Rotation::createFromDictionary(
|
||||
*p.transform->rotation
|
||||
);
|
||||
|
||||
// @TODO(abock, 2021-03-05) I don't think this is necessary anymore as we
|
||||
// transitioned to throwing exceptions when the construction fails
|
||||
if (result->_transform.rotation == nullptr) {
|
||||
LERROR(fmt::format(
|
||||
"Failed to create rotation for SceneGraphNode '{}'",
|
||||
result->identifier()
|
||||
));
|
||||
return nullptr;
|
||||
}
|
||||
LDEBUG(fmt::format(
|
||||
"Successfully created rotation for '{}'", result->identifier()
|
||||
));
|
||||
result->addPropertySubOwner(result->_transform.rotation.get());
|
||||
}
|
||||
|
||||
if (p.transform->scale.has_value()) {
|
||||
result->_transform.scale = Scale::createFromDictionary(*p.transform->scale);
|
||||
|
||||
// @TODO(abock, 2021-03-05) I don't think this is necessary anymore as we
|
||||
// transitioned to throwing exceptions when the construction fails
|
||||
if (result->_transform.scale == nullptr) {
|
||||
LERROR(fmt::format(
|
||||
"Failed to create scale for SceneGraphNode '{}'",
|
||||
result->identifier()
|
||||
));
|
||||
return nullptr;
|
||||
}
|
||||
LDEBUG(fmt::format(
|
||||
"Successfully created scale for '{}'", result->identifier()
|
||||
));
|
||||
result->addPropertySubOwner(result->_transform.scale.get());
|
||||
}
|
||||
LDEBUG(fmt::format(
|
||||
"Successfully created ephemeris for '{}'", result->identifier()
|
||||
));
|
||||
}
|
||||
if (result->_transform.translation) {
|
||||
result->addPropertySubOwner(result->_transform.translation.get());
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyTransformRotation)) {
|
||||
ghoul::Dictionary rotationDictionary =
|
||||
dictionary.value<ghoul::Dictionary>(KeyTransformRotation);
|
||||
result->_transform.rotation = Rotation::createFromDictionary(rotationDictionary);
|
||||
if (result->_transform.rotation == nullptr) {
|
||||
LERROR(fmt::format(
|
||||
"Failed to create rotation for SceneGraphNode '{}'", result->identifier()
|
||||
));
|
||||
return nullptr;
|
||||
}
|
||||
LDEBUG(fmt::format(
|
||||
"Successfully created rotation for '{}'", result->identifier()
|
||||
));
|
||||
}
|
||||
if (result->_transform.rotation) {
|
||||
result->addPropertySubOwner(result->_transform.rotation.get());
|
||||
}
|
||||
if (p.timeFrame.has_value()) {
|
||||
result->_timeFrame = TimeFrame::createFromDictionary(*p.timeFrame);
|
||||
|
||||
if (dictionary.hasKey(KeyTransformScale)) {
|
||||
ghoul::Dictionary scaleDictionary =
|
||||
dictionary.value<ghoul::Dictionary>(KeyTransformScale);
|
||||
result->_transform.scale = Scale::createFromDictionary(scaleDictionary);
|
||||
if (result->_transform.scale == nullptr) {
|
||||
LERROR(fmt::format(
|
||||
"Failed to create scale for SceneGraphNode '{}'", result->identifier()
|
||||
));
|
||||
return nullptr;
|
||||
}
|
||||
LDEBUG(fmt::format("Successfully created scale for '{}'", result->identifier()));
|
||||
}
|
||||
if (result->_transform.scale) {
|
||||
result->addPropertySubOwner(result->_transform.scale.get());
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyTimeFrame)) {
|
||||
ghoul::Dictionary timeFrameDictionary =
|
||||
dictionary.value<ghoul::Dictionary>(KeyTimeFrame);
|
||||
result->_timeFrame = TimeFrame::createFromDictionary(timeFrameDictionary);
|
||||
// @TODO(abock, 2021-03-05) I don't think this is necessary anymore as we
|
||||
// transitioned to throwing exceptions when the construction fails
|
||||
if (result->_timeFrame == nullptr) {
|
||||
LERROR(fmt::format(
|
||||
"Failed to create time frame for SceneGraphNode '{}'",
|
||||
@@ -252,30 +335,26 @@ ghoul::mm_unique_ptr<SceneGraphNode> SceneGraphNode::createFromDictionary(
|
||||
));
|
||||
return nullptr;
|
||||
}
|
||||
result->addPropertySubOwner(result->_timeFrame.get());
|
||||
LDEBUG(fmt::format(
|
||||
"Successfully created time frame for '{}'",
|
||||
result->identifier()
|
||||
"Successfully created time frame for '{}'", result->identifier()
|
||||
));
|
||||
result->addPropertySubOwner(result->_timeFrame.get());
|
||||
}
|
||||
|
||||
// We initialize the renderable last as it probably has the most dependencies
|
||||
if (dictionary.hasValue<ghoul::Dictionary>(KeyRenderable)) {
|
||||
ghoul::Dictionary renderableDictionary =
|
||||
dictionary.value<ghoul::Dictionary>(KeyRenderable);
|
||||
|
||||
result->_renderable = Renderable::createFromDictionary(renderableDictionary);
|
||||
if (p.renderable.has_value()) {
|
||||
result->_renderable = Renderable::createFromDictionary(*p.renderable);
|
||||
ghoul_assert(result->_renderable, "Failed to create Renderable");
|
||||
result->addPropertySubOwner(result->_renderable.get());
|
||||
LDEBUG(fmt::format(
|
||||
"Successfully created renderable for '{}'", result->identifier()
|
||||
));
|
||||
|
||||
// If the renderable child has a larger bounding sphere, we allow it tooverride
|
||||
// If the renderable child has a larger bounding sphere, we allow it to override
|
||||
if (result->_renderable->boundingSphere() > result->_boundingSphere) {
|
||||
result->_boundingSphere = result->_renderable->boundingSphere();
|
||||
|
||||
if (dictionary.hasKey(BoundingSphereInfo.identifier)) {
|
||||
if (p.boundingSphere.has_value()) {
|
||||
LWARNING(fmt::format(
|
||||
"The specified property 'BoundingSphere' for '{}' was overwritten "
|
||||
"by a child renderable",
|
||||
@@ -285,37 +364,34 @@ ghoul::mm_unique_ptr<SceneGraphNode> SceneGraphNode::createFromDictionary(
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyTag)) {
|
||||
if (dictionary.hasValue<std::string>(KeyTag)) {
|
||||
std::string tagName = dictionary.value<std::string>(KeyTag);
|
||||
if (!tagName.empty()) {
|
||||
result->addTag(std::move(tagName));
|
||||
}
|
||||
if (p.tag.has_value()) {
|
||||
if (std::holds_alternative<std::string>(*p.tag)) {
|
||||
result->addTag(std::get<std::string>(*p.tag));
|
||||
}
|
||||
else if (dictionary.hasValue<ghoul::Dictionary>(KeyTag)) {
|
||||
ghoul::Dictionary tagNames = dictionary.value<ghoul::Dictionary>(KeyTag);
|
||||
std::string tagName;
|
||||
for (std::string_view key : tagNames.keys()) {
|
||||
tagName = tagNames.value<std::string>(key);
|
||||
if (!tagName.empty()) {
|
||||
result->addTag(std::move(tagName));
|
||||
else if (std::holds_alternative<std::vector<std::string>>(*p.tag)) {
|
||||
for (const std::string& tag : std::get<std::vector<std::string>>(*p.tag)) {
|
||||
if (!tag.empty()) {
|
||||
result->addTag(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyGuiPath)) {
|
||||
result->_guiPath = dictionary.value<std::string>(KeyGuiPath);
|
||||
result->addProperty(result->_guiPath);
|
||||
}
|
||||
|
||||
|
||||
LDEBUG(fmt::format("Successfully created SceneGraphNode '{}'", result->identifier()));
|
||||
|
||||
result->_lastScreenSpaceUpdateTime = std::chrono::high_resolution_clock::now();
|
||||
return result;
|
||||
}
|
||||
|
||||
documentation::Documentation SceneGraphNode::Documentation() {
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "core_scene_node";
|
||||
return doc;
|
||||
}
|
||||
|
||||
SceneGraphNode::SceneGraphNode()
|
||||
: properties::PropertyOwner({ "" })
|
||||
, _guiHidden(GuiHiddenInfo)
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation SceneGraphNode::Documentation() {
|
||||
using namespace documentation;
|
||||
|
||||
return {
|
||||
"Scenegraph Node",
|
||||
"core_scene_node",
|
||||
{
|
||||
{
|
||||
"Identifier",
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The identifier of this scenegraph node. This name must be unique among all "
|
||||
"scene graph nodes that are loaded in a specific scene. If a duplicate is "
|
||||
"detected the loading of the node will fail, as will all childing that "
|
||||
"depend on the node. The identifier must not contain any whitespaces or '.'."
|
||||
},
|
||||
{
|
||||
"Parent",
|
||||
new StringAnnotationVerifier(
|
||||
"If specified, this must be a name for another scenegraph node"
|
||||
),
|
||||
Optional::Yes,
|
||||
"This names the parent of the currently specified scenegraph node. The "
|
||||
"parent must already exist in the scene graph. If not specified, the node "
|
||||
"will be attached to the root of the scenegraph.",
|
||||
},
|
||||
{
|
||||
"Renderable",
|
||||
new ReferencingVerifier("renderable"),
|
||||
Optional::Yes,
|
||||
"The renderable that is to be created for this scenegraph node. A renderable "
|
||||
"is a component of a scenegraph node that will lead to some visual result on "
|
||||
"the screen. The specifics heavily depend on the 'Type' of the renderable. "
|
||||
"If no Renderable is specified, this scenegraph node is an internal node and "
|
||||
"can be used for either group children, or apply common transformations to a "
|
||||
"group of children."
|
||||
},
|
||||
{
|
||||
"Transform",
|
||||
new TableVerifier({
|
||||
{
|
||||
"Translation",
|
||||
new ReferencingVerifier("core_transform_translation"),
|
||||
Optional::Yes,
|
||||
"This node describes a translation that is applied to the scenegraph "
|
||||
"node and all its children. Depending on the 'Type' of the "
|
||||
"translation, this can either be a static translation or a "
|
||||
"time-varying one."
|
||||
},
|
||||
{
|
||||
"Rotation",
|
||||
new ReferencingVerifier("core_transform_rotation"),
|
||||
Optional::Yes,
|
||||
"This nodes describes a rotation that is applied to the scenegraph "
|
||||
"node and all its children. Depending on the 'Type' of the rotation, "
|
||||
"this can either be a static rotation or a time-varying one."
|
||||
},
|
||||
{
|
||||
"Scale",
|
||||
new ReferencingVerifier("core_transform_scaling"),
|
||||
Optional::Yes,
|
||||
"This node describes a scaling that is applied to the scenegraph "
|
||||
"node and all its children. Depending on the 'Type' of the scaling, "
|
||||
"this can either be a static scaling or a time-varying one."
|
||||
}
|
||||
}),
|
||||
Optional::Yes,
|
||||
"This describes a set of transformations that are applied to this scenegraph "
|
||||
"node and all of its children. There are only three possible values "
|
||||
"corresponding to a 'Translation', a 'Rotation', and a 'Scale'."
|
||||
},
|
||||
{
|
||||
"TimeFrame",
|
||||
new ReferencingVerifier("core_time_frame"),
|
||||
Optional::Yes,
|
||||
"Specifies the time frame for when this node should be active."
|
||||
},
|
||||
{
|
||||
"GUI",
|
||||
new TableVerifier({
|
||||
{
|
||||
"Name",
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"An optional user-facing name for this SceneGraphNode, which does "
|
||||
"not have to be unique, though it is recommended, and can contain "
|
||||
"any characters."
|
||||
},
|
||||
{
|
||||
"Path",
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"If this value is specified, this '/' separated URI specifies the "
|
||||
"location of this scenegraph node in a GUI representation, for "
|
||||
"instance '/SolarSystem/Earth/Moon'."
|
||||
},
|
||||
{
|
||||
"Hidden",
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
"If this value is specified, GUI applications are incouraged to "
|
||||
"ignore this scenegraph node. This is most useful to trim collective "
|
||||
"lists of nodes and not display, for example, barycenters."
|
||||
}
|
||||
}),
|
||||
Optional::Yes,
|
||||
"Additional information that is passed to GUI applications. These are all "
|
||||
"hints and do not have any impact on the actual function of the scenegraph "
|
||||
"node."
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
@@ -34,45 +34,33 @@
|
||||
#include <ghoul/misc/templatefactory.h>
|
||||
|
||||
namespace {
|
||||
const char* KeyType = "Type";
|
||||
struct [[codegen::Dictionary(Translation)]] Parameters {
|
||||
// The type of translation that is described in this element. The available types
|
||||
// of translations depend on the configuration of the application and can be
|
||||
// written to disk on application startup into the FactoryDocumentation
|
||||
std::string type [[codegen::annotation("Must name a valid Translation type")]];
|
||||
};
|
||||
#include "translation_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation Translation::Documentation() {
|
||||
using namespace documentation;
|
||||
|
||||
return {
|
||||
"Transformation Translation",
|
||||
"core_transform_translation",
|
||||
{
|
||||
{
|
||||
KeyType,
|
||||
new StringAnnotationVerifier("Must name a valid Translation type"),
|
||||
Optional::No,
|
||||
"The type of translation that is described in this element. "
|
||||
"The available types of translations depend on the "
|
||||
"configuration of the application and can be written to disk "
|
||||
"on application startup into the FactoryDocumentation."
|
||||
}
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "core_transform_translation";
|
||||
return doc;
|
||||
}
|
||||
|
||||
ghoul::mm_unique_ptr<Translation> Translation::createFromDictionary(
|
||||
const ghoul::Dictionary& dictionary)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(Documentation(), dictionary, "Translation");
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
const std::string& translationType = dictionary.value<std::string>(KeyType);
|
||||
ghoul::TemplateFactory<Translation>* factory
|
||||
= FactoryManager::ref().factory<Translation>();
|
||||
Translation* result = factory->create(
|
||||
translationType,
|
||||
Translation* result = FactoryManager::ref().factory<Translation>()->create(
|
||||
p.type,
|
||||
dictionary,
|
||||
&global::memoryManager->PersistentMemory
|
||||
);
|
||||
result->setIdentifier("Translation");
|
||||
return ghoul::mm_unique_ptr<Translation>(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,68 +33,51 @@
|
||||
#include "scriptscheduler_lua.inl"
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyTime = "Time";
|
||||
constexpr const char* KeyForwardScript = "ForwardScript";
|
||||
constexpr const char* KeyBackwardScript = "BackwardScript";
|
||||
constexpr const char* KeyUniversalScript = "Script";
|
||||
struct [[codegen::Dictionary(ScheduledScript)]] Parameters {
|
||||
// The time at which, when the in game time passes it, the two scripts will
|
||||
// be executed. If the traversal is forwards (towards + infinity), the
|
||||
// ForwardScript will be executed, otherwise the BackwardScript will be
|
||||
// executed instead
|
||||
std::string time;
|
||||
|
||||
// The Lua script that will be executed when the specified time is passed
|
||||
// independent of its direction. This script will be executed before the
|
||||
// specific scripts if both versions are specified
|
||||
std::optional<std::string> script;
|
||||
|
||||
// The Lua script that is executed when OpenSpace passes the time in a
|
||||
// forward direction
|
||||
std::optional<std::string> forwardScript;
|
||||
|
||||
// The Lua script that is executed when OpenSpace passes the time in a
|
||||
// backward direction
|
||||
std::optional<std::string> backwardScript;
|
||||
};
|
||||
#include "scriptscheduler_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace::scripting {
|
||||
|
||||
documentation::Documentation ScriptScheduler::Documentation() {
|
||||
using namespace openspace::documentation;
|
||||
|
||||
using TimeVerifier = StringVerifier;
|
||||
using LuaScriptVerifier = StringVerifier;
|
||||
|
||||
return {
|
||||
"Scheduled Scripts",
|
||||
"core_scheduledscript",
|
||||
{
|
||||
{
|
||||
"*",
|
||||
new TableVerifier({
|
||||
{
|
||||
KeyTime,
|
||||
new TimeVerifier,
|
||||
Optional::No,
|
||||
"The time at which, when the in game time passes it, the two "
|
||||
"scripts will be executed. If the traversal is forwards (towards "
|
||||
"+ infinity), the ForwardScript will be executed, otherwise the "
|
||||
"BackwardScript will be executed instead."
|
||||
},
|
||||
{
|
||||
KeyUniversalScript,
|
||||
new LuaScriptVerifier,
|
||||
Optional::Yes,
|
||||
"The Lua script that will be executed when the specified time is "
|
||||
"passed independent of its direction. This script will be "
|
||||
"executed before the specific scripts if both versions are "
|
||||
"specified"
|
||||
},
|
||||
{
|
||||
KeyForwardScript,
|
||||
new LuaScriptVerifier,
|
||||
Optional::Yes,
|
||||
"The Lua script that is executed when OpenSpace passes the time "
|
||||
"in a forward direction."
|
||||
},
|
||||
{
|
||||
KeyBackwardScript,
|
||||
new LuaScriptVerifier,
|
||||
Optional::Yes,
|
||||
"The Lua script that is executed when OpenSpace passes the time "
|
||||
"in a backward direction."
|
||||
}
|
||||
}),
|
||||
Optional::No
|
||||
}
|
||||
}
|
||||
};
|
||||
// @TODO (abock, 2021-03-25) This is not really correct. This function currently
|
||||
// returns the documentation for the ScheduledScript, not for the ScriptScheduler
|
||||
// itself. This should be cleaned up a bit
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "core_scheduledscript";
|
||||
return doc;
|
||||
}
|
||||
|
||||
using namespace openspace::interaction;
|
||||
|
||||
ScriptScheduler::ScheduledScript::ScheduledScript(const ghoul::Dictionary& dict) {
|
||||
const Parameters p = codegen::bake<Parameters>(dict);
|
||||
|
||||
time = Time::convertTime(p.time);
|
||||
forwardScript = p.forwardScript.value_or(forwardScript);
|
||||
backwardScript = p.backwardScript.value_or(backwardScript);
|
||||
universalScript = p.script.value_or(universalScript);
|
||||
}
|
||||
|
||||
void ScriptScheduler::loadScripts(std::vector<ScheduledScript> scheduledScripts) {
|
||||
// Sort scripts by time; use a stable_sort as the user might have had an intention
|
||||
// specifying multiple scripts for the same time in a specific order
|
||||
|
||||
@@ -38,35 +38,20 @@ int loadFile(lua_State* L) {
|
||||
return ghoul::lua::luaError(L, "filepath string is empty");
|
||||
}
|
||||
|
||||
ghoul::Dictionary scriptsDict = ghoul::lua::loadDictionaryFromFile(fileName, L);
|
||||
ghoul::Dictionary scriptsDict;
|
||||
scriptsDict.setValue("Scripts", ghoul::lua::loadDictionaryFromFile(fileName, L));
|
||||
documentation::testSpecificationAndThrow(
|
||||
scripting::ScriptScheduler::Documentation(),
|
||||
scriptsDict,
|
||||
"ScriptScheduler"
|
||||
);
|
||||
|
||||
|
||||
std::vector<scripting::ScriptScheduler::ScheduledScript> scripts;
|
||||
for (int i = 1; i <= scriptsDict.size(); ++i) {
|
||||
for (size_t i = 1; i <= scriptsDict.size(); ++i) {
|
||||
ghoul::Dictionary d = scriptsDict.value<ghoul::Dictionary>(std::to_string(i));
|
||||
|
||||
scripting::ScriptScheduler::ScheduledScript script;
|
||||
constexpr const char* KeyTime = "Time";
|
||||
if (d.hasValue<std::string>(KeyTime)) {
|
||||
script.time = Time::convertTime(d.value<std::string>(KeyTime));
|
||||
}
|
||||
constexpr const char* KeyForwardScript = "ForwardScript";
|
||||
if (d.hasValue<std::string>(KeyForwardScript)) {
|
||||
script.forwardScript = d.value<std::string>(KeyForwardScript);
|
||||
}
|
||||
constexpr const char* KeyBackwardScript = "BackwardScript";
|
||||
if (d.hasValue<std::string>(KeyBackwardScript)) {
|
||||
script.backwardScript = d.value<std::string>(KeyBackwardScript);
|
||||
}
|
||||
constexpr const char* KeyUniversalScript = "Script";
|
||||
if (d.hasValue<std::string>(KeyUniversalScript)) {
|
||||
script.universalScript = d.value<std::string>(KeyUniversalScript);
|
||||
}
|
||||
scripting::ScriptScheduler::ScheduledScript script =
|
||||
scripting::ScriptScheduler::ScheduledScript(d);
|
||||
scripts.push_back(script);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,67 +30,41 @@
|
||||
#include <ghoul/misc/templatefactory.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyType = "Type";
|
||||
constexpr const char* KeyName = "Name";
|
||||
struct [[codegen::Dictionary(ResourceSynchronization)]] Parameters {
|
||||
// This key specifies the type of ResourceSyncrhonization that gets created. It
|
||||
// has to be one of the valid ResourceSyncrhonizations that are available for
|
||||
// creation (see the FactoryDocumentation for a list of possible
|
||||
// ResourceSyncrhonizations), which depends on the configration of the application
|
||||
std::string type
|
||||
[[codegen::annotation("A ResourceSynchronization created by a factory")]];
|
||||
|
||||
// A user readable name of this synchronization
|
||||
std::string name;
|
||||
};
|
||||
#include "resourcesynchronization_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation ResourceSynchronization::Documentation() {
|
||||
using namespace openspace::documentation;
|
||||
|
||||
return {
|
||||
"ResourceSynchronization",
|
||||
"resourceSynchronization",
|
||||
{
|
||||
{
|
||||
KeyType,
|
||||
new StringAnnotationVerifier(
|
||||
"A valid ResourceSyncrhonization created by a factory"
|
||||
),
|
||||
Optional::No,
|
||||
"This key specifies the type of ResourceSyncrhonization that gets "
|
||||
"created. It has to be one of the valid ResourceSyncrhonizations that "
|
||||
"are available for creation (see the FactoryDocumentation for a list of "
|
||||
"possible ResourceSyncrhonizations), which depends on the configration "
|
||||
"of the application"
|
||||
},
|
||||
{
|
||||
KeyName,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"A user readable name of this synchronization"
|
||||
},
|
||||
}
|
||||
};
|
||||
documentation::Documentation doc = codegen::doc<Parameters>();
|
||||
doc.id = "resourceSynchronization";
|
||||
return doc;
|
||||
}
|
||||
|
||||
std::unique_ptr<ResourceSynchronization> ResourceSynchronization::createFromDictionary(
|
||||
const ghoul::Dictionary& dictionary)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"ResourceSynchronization"
|
||||
);
|
||||
|
||||
const std::string& synchronizationType = dictionary.value<std::string>(KeyType);
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
auto factory = FactoryManager::ref().factory<ResourceSynchronization>();
|
||||
ghoul_assert(factory, "ResourceSynchronization factory did not exist");
|
||||
ResourceSynchronization* sync = factory->create(synchronizationType, dictionary);
|
||||
ResourceSynchronization* sync = factory->create(p.type, dictionary);
|
||||
sync->_name = p.name;
|
||||
return std::unique_ptr<ResourceSynchronization>(sync);
|
||||
}
|
||||
|
||||
ResourceSynchronization::ResourceSynchronization(const ghoul::Dictionary& dictionary) {
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"ResourceSynchronization"
|
||||
);
|
||||
|
||||
_name = dictionary.value<std::string>(KeyName);
|
||||
}
|
||||
ResourceSynchronization::ResourceSynchronization(const ghoul::Dictionary&) {}
|
||||
|
||||
ResourceSynchronization::State ResourceSynchronization::state() const {
|
||||
return _state;
|
||||
@@ -111,14 +85,14 @@ bool ResourceSynchronization::isSyncing() const {
|
||||
ResourceSynchronization::CallbackHandle
|
||||
ResourceSynchronization::addStateChangeCallback(StateChangeCallback cb)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(_callbackMutex);
|
||||
std::lock_guard guard(_callbackMutex);
|
||||
CallbackHandle callbackId = _nextCallbackId++;
|
||||
_stateChangeCallbacks[callbackId] = std::move(cb);
|
||||
return callbackId;
|
||||
}
|
||||
|
||||
void ResourceSynchronization::removeStateChangeCallback(CallbackHandle id) {
|
||||
std::lock_guard<std::mutex> guard(_callbackMutex);
|
||||
std::lock_guard guard(_callbackMutex);
|
||||
_stateChangeCallbacks.erase(id);
|
||||
}
|
||||
|
||||
|
||||
@@ -586,7 +586,7 @@ std::string SpiceManager::dateFromEphemerisTime(double ephemerisTime, const char
|
||||
ephemerisTime, format
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
return std::string(Buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"""
|
||||
OpenSpace
|
||||
|
||||
Copyright (c) 2014-2020
|
||||
Copyright (c) 2014-2021
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
software and associated documentation files (the "Software"), to deal in the Software
|
||||
@@ -59,7 +59,7 @@ import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
current_year = '2020'
|
||||
current_year = '2021'
|
||||
is_strict_mode = False
|
||||
is_silent_mode = False
|
||||
|
||||
@@ -659,19 +659,23 @@ if not is_silent_mode:
|
||||
|
||||
check_files(
|
||||
[basePath + 'src/**/*.cpp'],
|
||||
[],
|
||||
[basePath + 'src/**/*_codegen.cpp'],
|
||||
'openspace_core',
|
||||
check_source_file
|
||||
)
|
||||
check_files(
|
||||
[basePath + 'apps/**/*.cpp'],
|
||||
[basePath + 'apps/**/ext/**/*.cpp'],
|
||||
[basePath + 'apps/**/ext/**/*.cpp', basePath + 'apps/**/*_codegen.cpp'],
|
||||
'openspace_app',
|
||||
check_source_file
|
||||
)
|
||||
check_files(
|
||||
[basePath + 'modules/**/*.cpp'],
|
||||
[basePath + 'modules/**/ext/**/*.cpp', basePath + 'modules/**/node_modules/**/*.cpp'],
|
||||
[
|
||||
basePath + 'modules/**/ext/**/*.cpp',
|
||||
basePath + 'modules/**/node_modules/**/*.cpp',
|
||||
basePath + 'modules/**/*_codegen.cpp'
|
||||
],
|
||||
'openspace_module',
|
||||
check_source_file
|
||||
)
|
||||
|
||||
Submodule support/coding/codegen updated: 9c54077384...73fb9593db
Reference in New Issue
Block a user