mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-03-13 17:09:05 -05:00
Merging master in to sync with new release
This commit is contained in:
@@ -39,7 +39,6 @@
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "RenderableNodeLine";
|
||||
constexpr const char* ProgramName = "NodeLineProgram";
|
||||
constexpr const char* Root = "Root";
|
||||
|
||||
|
||||
@@ -70,8 +70,8 @@ protected:
|
||||
void createPlane();
|
||||
|
||||
properties::OptionProperty _blendMode;
|
||||
properties::BoolProperty _mirrorBackside;
|
||||
properties::BoolProperty _billboard;
|
||||
properties::BoolProperty _mirrorBackside;
|
||||
properties::FloatProperty _size;
|
||||
properties::Vec3Property _multiplyColor;
|
||||
|
||||
|
||||
@@ -208,6 +208,8 @@ void RenderablePlaneTimeVaryingImage::update(const UpdateData& data) {
|
||||
if (isInInterval) {
|
||||
const size_t nextIdx = _activeTriggerTimeIndex + 1;
|
||||
if (
|
||||
// true => we were not in an interval the previous frame but now we are
|
||||
_activeTriggerTimeIndex == -1 ||
|
||||
// true => We stepped back to a time represented by another state
|
||||
currentTime < _startTimes[_activeTriggerTimeIndex] ||
|
||||
// true => We stepped forward to a time represented by another state
|
||||
|
||||
@@ -144,7 +144,7 @@ documentation::Documentation RenderableTrailOrbit::Documentation() {
|
||||
|
||||
RenderableTrailOrbit::RenderableTrailOrbit(const ghoul::Dictionary& dictionary)
|
||||
: RenderableTrail(dictionary)
|
||||
, _period(PeriodInfo, 0.0, 0.0, 1e9)
|
||||
, _period(PeriodInfo, 0.0, 0.0, 250.0 * 365.25) // 250 years should be enough I guess
|
||||
, _resolution(ResolutionInfo, 10000, 1, 1000000)
|
||||
{
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
@@ -152,10 +152,9 @@ RenderableTrailOrbit::RenderableTrailOrbit(const ghoul::Dictionary& dictionary)
|
||||
_translation->onParameterChange([this]() { _needsFullSweep = true; });
|
||||
|
||||
// Period is in days
|
||||
using namespace std::chrono;
|
||||
_period = p.period * duration_cast<seconds>(hours(24)).count();
|
||||
_period = p.period;
|
||||
_period.onChange([&] { _needsFullSweep = true; _indexBufferDirty = true; });
|
||||
_period.setExponent(5.f);
|
||||
_period.setExponent(3.f);
|
||||
addProperty(_period);
|
||||
|
||||
_resolution = p.resolution;
|
||||
@@ -368,7 +367,9 @@ RenderableTrailOrbit::UpdateReport RenderableTrailOrbit::updateTrails(
|
||||
return { false, false, 0 };
|
||||
}
|
||||
|
||||
const double secondsPerPoint = _period / (_resolution - 1);
|
||||
using namespace std::chrono;
|
||||
double periodSeconds = _period * duration_cast<seconds>(hours(24)).count();
|
||||
const double secondsPerPoint = periodSeconds / (_resolution - 1);
|
||||
// How much time has passed since the last permanent point
|
||||
const double delta = data.time.j2000Seconds() - _lastPointTime;
|
||||
|
||||
@@ -486,7 +487,9 @@ void RenderableTrailOrbit::fullSweep(double time) {
|
||||
|
||||
_lastPointTime = time;
|
||||
|
||||
const double secondsPerPoint = _period / (_resolution - 1);
|
||||
using namespace std::chrono;
|
||||
const double periodSeconds = _period * duration_cast<seconds>(hours(24)).count();
|
||||
const double secondsPerPoint = periodSeconds / (_resolution - 1);
|
||||
// starting at 1 because the first position is a floating current one
|
||||
for (int i = 1; i < _resolution; ++i) {
|
||||
const glm::vec3 p = _translation->position({ {}, Time(time), Time(0.0) });
|
||||
|
||||
@@ -97,7 +97,7 @@ bool ScreenSpaceFramebuffer::deinitializeGL() {
|
||||
|
||||
_framebuffer->activate();
|
||||
_framebuffer->detachAll();
|
||||
_framebuffer->deactivate();
|
||||
ghoul::opengl::FramebufferObject::deactivate();
|
||||
removeAllRenderFunctions();
|
||||
|
||||
return true;
|
||||
@@ -122,7 +122,7 @@ void ScreenSpaceFramebuffer::render() {
|
||||
);
|
||||
global::renderEngine->openglStateCache().setViewportState(viewport);
|
||||
|
||||
GLint defaultFBO = _framebuffer->getActiveObject();
|
||||
GLint defaultFBO = ghoul::opengl::FramebufferObject::getActiveObject();
|
||||
_framebuffer->activate();
|
||||
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
@@ -130,7 +130,7 @@ void ScreenSpaceFramebuffer::render() {
|
||||
for (const RenderFunction& renderFunction : _renderFunctions) {
|
||||
renderFunction();
|
||||
}
|
||||
_framebuffer->deactivate();
|
||||
ghoul::opengl::FramebufferObject::deactivate();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
|
||||
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
@@ -185,7 +185,7 @@ void ScreenSpaceFramebuffer::createFramebuffer() {
|
||||
_texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
||||
_texture->purgeFromRAM();
|
||||
_framebuffer->attachTexture(_texture.get(), GL_COLOR_ATTACHMENT0);
|
||||
_framebuffer->deactivate();
|
||||
ghoul::opengl::FramebufferObject::deactivate();
|
||||
}
|
||||
|
||||
int ScreenSpaceFramebuffer::id() {
|
||||
|
||||
@@ -485,6 +485,20 @@ bool FixedRotation::initialize() {
|
||||
return res;
|
||||
}
|
||||
|
||||
void FixedRotation::update(const UpdateData& data) {
|
||||
bool anyAxisIsObjectType = (
|
||||
_xAxis.type == Axis::Type::Object ||
|
||||
_yAxis.type == Axis::Type::Object ||
|
||||
_zAxis.type == Axis::Type::Object
|
||||
);
|
||||
|
||||
if (_attachedNode || anyAxisIsObjectType) {
|
||||
requireUpdate();
|
||||
}
|
||||
|
||||
Rotation::update(data);
|
||||
}
|
||||
|
||||
glm::dmat3 FixedRotation::matrix(const UpdateData&) const {
|
||||
if (!_enabled) {
|
||||
return glm::dmat3();
|
||||
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
void update(const UpdateData& data) override;
|
||||
glm::dmat3 matrix(const UpdateData& data) const override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -59,12 +59,12 @@ namespace {
|
||||
constexpr const char* ProgramObjectName = "RenderableBillboardsCloud";
|
||||
constexpr const char* RenderToPolygonProgram = "RenderableBillboardsCloud_Polygon";
|
||||
|
||||
constexpr const std::array<const char*, 20> UniformNames = {
|
||||
constexpr const std::array<const char*, 21> UniformNames = {
|
||||
"cameraViewProjectionMatrix", "modelMatrix", "cameraPosition", "cameraLookUp",
|
||||
"renderOption", "minBillboardSize", "maxBillboardSize",
|
||||
"correctionSizeEndDistance", "correctionSizeFactor", "color", "alphaValue",
|
||||
"scaleFactor", "up", "right", "fadeInValue", "screenSize", "spriteTexture",
|
||||
"hasColorMap", "enabledRectSizeControl", "hasDvarScaling"
|
||||
"hasColorMap", "useColorMap", "enabledRectSizeControl", "hasDvarScaling"
|
||||
};
|
||||
|
||||
enum RenderOption {
|
||||
@@ -85,6 +85,14 @@ namespace {
|
||||
"size of each point."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo UseColorMapInfo = {
|
||||
"UseColorMap",
|
||||
"Use Color Map",
|
||||
"If this value is set to 'true', the provided color map is used (if one was "
|
||||
"provided in the configuration). If no color map was provided, changing this "
|
||||
"setting does not do anything."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ColorInfo = {
|
||||
"Color",
|
||||
"Color",
|
||||
@@ -253,6 +261,9 @@ namespace {
|
||||
// [[codegen::verbatim(ScaleFactorInfo.description)]]
|
||||
std::optional<float> scaleFactor;
|
||||
|
||||
// [[codegen::verbatim(UseColorMapInfo.description)]]
|
||||
std::optional<bool> useColorMap;
|
||||
|
||||
// [[codegen::verbatim(ColorMapInfo.description)]]
|
||||
std::optional<std::string> colorMap;
|
||||
|
||||
@@ -328,6 +339,7 @@ documentation::Documentation RenderableBillboardsCloud::Documentation() {
|
||||
RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& dictionary)
|
||||
: Renderable(dictionary)
|
||||
, _scaleFactor(ScaleFactorInfo, 1.f, 0.f, 600.f)
|
||||
, _useColorMap(UseColorMapInfo, true)
|
||||
, _pointColor(ColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f))
|
||||
, _spriteTexturePath(SpriteTextureInfo)
|
||||
, _textColor(TextColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f))
|
||||
@@ -374,6 +386,8 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di
|
||||
}
|
||||
_hasSpeckFile = p.file.has_value();
|
||||
|
||||
_useColorMap = p.useColorMap.value_or(_useColorMap);
|
||||
|
||||
_drawElements = p.drawElements.value_or(_drawElements);
|
||||
_drawElements.onChange([&]() { _hasSpeckFile = !_hasSpeckFile; });
|
||||
addProperty(_drawElements);
|
||||
@@ -440,11 +454,10 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di
|
||||
|
||||
_isColorMapExact = p.exactColorMap.value_or(_isColorMapExact);
|
||||
}
|
||||
else {
|
||||
_pointColor = p.color;
|
||||
_pointColor.setViewOption(properties::Property::ViewOptions::Color);
|
||||
addProperty(_pointColor);
|
||||
}
|
||||
|
||||
_pointColor = p.color;
|
||||
_pointColor.setViewOption(properties::Property::ViewOptions::Color);
|
||||
addProperty(_pointColor);
|
||||
|
||||
addProperty(_opacity);
|
||||
|
||||
@@ -538,6 +551,9 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di
|
||||
});
|
||||
addProperty(_setRangeFromData);
|
||||
|
||||
_useColorMap.onChange([this]() { _dataIsDirty = true; });
|
||||
addProperty(_useColorMap);
|
||||
|
||||
_useLinearFiltering = p.useLinearFiltering.value_or(_useLinearFiltering);
|
||||
_useLinearFiltering.onChange([&]() { _dataIsDirty = true; });
|
||||
addProperty(_useLinearFiltering);
|
||||
@@ -713,6 +729,7 @@ void RenderableBillboardsCloud::renderBillboards(const RenderData& data,
|
||||
}
|
||||
_program->setUniform(_uniformCache.spriteTexture, textureUnit);
|
||||
_program->setUniform(_uniformCache.hasColormap, _hasColorMapFile);
|
||||
_program->setUniform(_uniformCache.useColormap, _useColorMap);
|
||||
|
||||
glBindVertexArray(_vao);
|
||||
glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(_dataset.entries.size()));
|
||||
@@ -972,7 +989,8 @@ std::vector<float> RenderableBillboardsCloud::createDataSlice() {
|
||||
}
|
||||
|
||||
// what datavar in use for the index color
|
||||
int colorMapInUse = _hasColorMapFile ? _dataset.index(_colorOptionString) : 0;
|
||||
int colorMapInUse =
|
||||
_hasColorMapFile ? _dataset.index(_colorOptionString) : 0;
|
||||
|
||||
// what datavar in use for the size scaling (if present)
|
||||
int sizeScalingInUse =
|
||||
@@ -1035,7 +1053,7 @@ std::vector<float> RenderableBillboardsCloud::createDataSlice() {
|
||||
const double r = glm::length(p);
|
||||
maxRadius = std::max(maxRadius, r);
|
||||
|
||||
if (_hasColorMapFile) {
|
||||
if (_hasColorMapFile && _useColorMap && !_colorMap.entries.empty()) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
result.push_back(position[j]);
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ private:
|
||||
GLuint _pTexture = 0;
|
||||
|
||||
properties::FloatProperty _scaleFactor;
|
||||
properties::BoolProperty _useColorMap;
|
||||
properties::Vec3Property _pointColor;
|
||||
properties::StringProperty _spriteTexturePath;
|
||||
properties::Vec3Property _textColor;
|
||||
@@ -128,7 +129,8 @@ private:
|
||||
cameraViewProjectionMatrix, modelMatrix, cameraPos, cameraLookup, renderOption,
|
||||
minBillboardSize, maxBillboardSize, correctionSizeEndDistance,
|
||||
correctionSizeFactor, color, alphaValue, scaleFactor, up, right, fadeInValue,
|
||||
screenSize, spriteTexture, hasColormap, enabledRectSizeControl, hasDvarScaling
|
||||
screenSize, spriteTexture, hasColormap, useColormap, enabledRectSizeControl,
|
||||
hasDvarScaling
|
||||
) _uniformCache;
|
||||
|
||||
std::shared_ptr<ghoul::fontrendering::Font> _font;
|
||||
|
||||
@@ -359,7 +359,7 @@ void RenderablePoints::readColorMapFile() {
|
||||
// std::streampos position = file.tellg();
|
||||
std::getline(file, line);
|
||||
|
||||
if (line[0] == '#' || line.empty()) {
|
||||
if (line.empty() || line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ uniform float alphaValue;
|
||||
uniform vec3 color;
|
||||
uniform sampler2D spriteTexture;
|
||||
uniform bool hasColorMap;
|
||||
uniform bool useColorMap;
|
||||
uniform float fadeInValue;
|
||||
|
||||
Fragment getFragment() {
|
||||
@@ -47,7 +48,7 @@ Fragment getFragment() {
|
||||
|
||||
vec4 fullColor = textureColor;
|
||||
|
||||
if (hasColorMap) {
|
||||
if (hasColorMap && useColorMap) {
|
||||
fullColor *= gs_colorMap;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -51,6 +51,12 @@
|
||||
#include "exoplanetsmodule_lua.inl"
|
||||
|
||||
namespace {
|
||||
constexpr const openspace::properties::Property::PropertyInfo EnabledInfo = {
|
||||
"Enabled",
|
||||
"Enabled",
|
||||
"Decides if the GUI for this module should be enabled."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo DataFolderInfo = {
|
||||
"DataFolder",
|
||||
"Data Folder",
|
||||
@@ -139,6 +145,9 @@ namespace {
|
||||
constexpr const char LookupTableFileName[] = "lookup.txt";
|
||||
|
||||
struct [[codegen::Dictionary(ExoplanetsModule)]] Parameters {
|
||||
// [[codegen::verbatim(EnabledInfo.description)]]
|
||||
std::optional<bool> enabled;
|
||||
|
||||
// [[codegen::verbatim(DataFolderInfo.description)]]
|
||||
std::optional<std::filesystem::path> dataFolder [[codegen::directory()]];
|
||||
|
||||
@@ -181,6 +190,7 @@ using namespace exoplanets;
|
||||
|
||||
ExoplanetsModule::ExoplanetsModule()
|
||||
: OpenSpaceModule(Name)
|
||||
, _enabled(EnabledInfo)
|
||||
, _exoplanetsDataFolder(DataFolderInfo)
|
||||
, _bvColorMapPath(BvColorMapInfo)
|
||||
, _starTexturePath(StarTextureInfo)
|
||||
@@ -191,10 +201,12 @@ ExoplanetsModule::ExoplanetsModule()
|
||||
, _showComparisonCircle(ShowComparisonCircleInfo, false)
|
||||
, _showHabitableZone(ShowHabitableZoneInfo, true)
|
||||
, _useOptimisticZone(UseOptimisticZoneInfo, true)
|
||||
, _habitableZoneOpacity(HabitableZoneOpacityInfo, 0.1f, 0.0f, 1.0f)
|
||||
, _habitableZoneOpacity(HabitableZoneOpacityInfo, 0.1f, 0.f, 1.f)
|
||||
{
|
||||
_exoplanetsDataFolder.setReadOnly(true);
|
||||
|
||||
addProperty(_enabled);
|
||||
|
||||
addProperty(_exoplanetsDataFolder);
|
||||
addProperty(_bvColorMapPath);
|
||||
addProperty(_starTexturePath);
|
||||
@@ -273,6 +285,8 @@ float ExoplanetsModule::habitableZoneOpacity() const {
|
||||
void ExoplanetsModule::internalInitialize(const ghoul::Dictionary& dict) {
|
||||
const Parameters p = codegen::bake<Parameters>(dict);
|
||||
|
||||
_enabled = p.enabled.value_or(true);
|
||||
|
||||
if (p.dataFolder.has_value()) {
|
||||
_exoplanetsDataFolder = p.dataFolder.value().string();
|
||||
}
|
||||
|
||||
@@ -74,6 +74,8 @@ protected:
|
||||
properties::BoolProperty _useOptimisticZone;
|
||||
|
||||
properties::FloatProperty _habitableZoneOpacity;
|
||||
|
||||
properties::BoolProperty _enabled;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace {
|
||||
"Color Table/Transfer Function to use for 'By Quantity' coloring."
|
||||
};
|
||||
constexpr openspace::properties::Property::PropertyInfo ColorUniformInfo = {
|
||||
"Uniform",
|
||||
"Color",
|
||||
"Uniform Line Color",
|
||||
"The uniform color of lines shown when 'Color Method' is set to 'Uniform'."
|
||||
};
|
||||
@@ -105,9 +105,9 @@ namespace {
|
||||
"Valid radial range. [Min, Max]"
|
||||
};
|
||||
constexpr openspace::properties::Property::PropertyInfo FlowColorInfo = {
|
||||
"Color",
|
||||
"Color",
|
||||
"Color of particles."
|
||||
"FlowColor",
|
||||
"Flow Color",
|
||||
"Color of particles flow direction indication."
|
||||
};
|
||||
constexpr openspace::properties::Property::PropertyInfo FlowEnabledInfo = {
|
||||
"FlowEnabled",
|
||||
@@ -197,6 +197,9 @@ namespace {
|
||||
// Set to true if you are streaming data during runtime
|
||||
std::optional<bool> loadAtRuntime;
|
||||
|
||||
// [[codegen::verbatim(ColorUniformInfo.description)]]
|
||||
std::optional<glm::vec4> color [[codegen::color()]];
|
||||
|
||||
// A list of paths to transferfunction .txt files containing color tables
|
||||
// used for colorizing the fieldlines according to different parameters
|
||||
std::optional<std::vector<std::string>> colorTablePaths;
|
||||
@@ -215,6 +218,21 @@ namespace {
|
||||
// would be traveling
|
||||
std::optional<bool> flowEnabled;
|
||||
|
||||
// [[codegen::verbatim(FlowColorInfo.description)]]
|
||||
std::optional<glm::vec4> flowColor [[codegen::color()]];
|
||||
|
||||
// [[codegen::verbatim(FlowReversedInfo.description)]]
|
||||
std::optional<bool> reversedFlow;
|
||||
|
||||
// [[codegen::verbatim(FlowParticleSizeInfo.description)]]
|
||||
std::optional<int> particleSize;
|
||||
|
||||
// [[codegen::verbatim(FlowParticleSpacingInfo.description)]]
|
||||
std::optional<int> particleSpacing;
|
||||
|
||||
// [[codegen::verbatim(FlowSpeedInfo.description)]]
|
||||
std::optional<int> flowSpeed;
|
||||
|
||||
// [[codegen::verbatim(MaskingEnabledInfo.description)]]
|
||||
std::optional<bool> maskingEnabled;
|
||||
|
||||
@@ -380,16 +398,29 @@ RenderableFieldlinesSequence::RenderableFieldlinesSequence(
|
||||
"{} contains no {} files", sourcePath.string(), fileTypeString
|
||||
));
|
||||
}
|
||||
|
||||
_extraVars = p.extraVariables.value_or(_extraVars);
|
||||
_flowEnabled = p.flowEnabled.value_or(_flowEnabled);
|
||||
_flowColor = p.flowColor.value_or(_flowColor);
|
||||
_flowReversed = p.reversedFlow.value_or(_flowReversed);
|
||||
_flowParticleSize = p.particleSize.value_or(_flowParticleSize);
|
||||
_flowParticleSpacing = p.particleSpacing.value_or(_flowParticleSpacing);
|
||||
_flowSpeed = p.flowSpeed.value_or(_flowSpeed);
|
||||
_lineWidth = p.lineWidth.value_or(_lineWidth);
|
||||
_manualTimeOffset = p.manualTimeOffset.value_or(_manualTimeOffset);
|
||||
_modelStr = p.simulationModel.value_or(_modelStr);
|
||||
_seedPointDirectory = p.seedPointDirectory.value_or(_seedPointDirectory);
|
||||
_maskingEnabled = p.maskingEnabled.value_or(_maskingEnabled);
|
||||
_maskingQuantityTemp = p.maskingQuantity.value_or(_maskingQuantityTemp);
|
||||
_colorTablePaths = p.colorTablePaths.value_or(_colorTablePaths);
|
||||
if (p.colorTablePaths.has_value()) {
|
||||
_colorTablePaths = p.colorTablePaths.value();
|
||||
}
|
||||
else {
|
||||
// Set a default color table, just in case the (optional) user defined paths are
|
||||
// corrupt or not provided
|
||||
_colorTablePaths.push_back(FieldlinesSequenceModule::DefaultTransferFunctionFile);
|
||||
}
|
||||
|
||||
_colorUniform = p.color.value_or(_colorUniform);
|
||||
|
||||
_colorMethod.addOption(static_cast<int>(ColorMethod::Uniform), "Uniform");
|
||||
_colorMethod.addOption(static_cast<int>(ColorMethod::ByQuantity), "By Quantity");
|
||||
@@ -442,12 +473,18 @@ RenderableFieldlinesSequence::RenderableFieldlinesSequence(
|
||||
}
|
||||
|
||||
void RenderableFieldlinesSequence::initialize() {
|
||||
// Set a default color table, just in case the (optional) user defined paths are
|
||||
// corrupt or not provided
|
||||
_colorTablePaths.push_back(FieldlinesSequenceModule::DefaultTransferFunctionFile);
|
||||
_transferFunction = std::make_unique<TransferFunction>(
|
||||
absPath(_colorTablePaths[0]).string()
|
||||
);
|
||||
}
|
||||
|
||||
void RenderableFieldlinesSequence::initializeGL() {
|
||||
// Setup shader program
|
||||
_shaderProgram = global::renderEngine->buildRenderProgram(
|
||||
"FieldlinesSequence",
|
||||
absPath("${MODULE_FIELDLINESSEQUENCE}/shaders/fieldlinessequence_vs.glsl"),
|
||||
absPath("${MODULE_FIELDLINESSEQUENCE}/shaders/fieldlinessequence_fs.glsl")
|
||||
);
|
||||
|
||||
// Extract source file type specific information from dictionary
|
||||
// & get states from source
|
||||
@@ -489,17 +526,7 @@ void RenderableFieldlinesSequence::initialize() {
|
||||
|
||||
computeSequenceEndTime();
|
||||
setModelDependentConstants();
|
||||
|
||||
setupProperties();
|
||||
}
|
||||
|
||||
void RenderableFieldlinesSequence::initializeGL() {
|
||||
// Setup shader program
|
||||
_shaderProgram = global::renderEngine->buildRenderProgram(
|
||||
"FieldlinesSequence",
|
||||
absPath("${MODULE_FIELDLINESSEQUENCE}/shaders/fieldlinessequence_vs.glsl"),
|
||||
absPath("${MODULE_FIELDLINESSEQUENCE}/shaders/fieldlinessequence_fs.glsl")
|
||||
);
|
||||
|
||||
glGenVertexArrays(1, &_vertexArrayObject);
|
||||
glGenBuffers(1, &_vertexPositionBuffer);
|
||||
@@ -552,6 +579,10 @@ bool RenderableFieldlinesSequence::prepareForOsflsStreaming() {
|
||||
}
|
||||
_states.push_back(newState);
|
||||
_nStates = _startTimes.size();
|
||||
if (_nStates == 1) {
|
||||
// loading dynamicaly is not nessesary if only having one set in the sequence
|
||||
_loadingStatesDynamically = false;
|
||||
}
|
||||
_activeStateIndex = 0;
|
||||
return true;
|
||||
}
|
||||
@@ -631,6 +662,7 @@ void RenderableFieldlinesSequence::setupProperties() {
|
||||
// Each quantity should have its own color table and color table range
|
||||
// no more, no less
|
||||
_colorTablePaths.resize(nExtraQuantities, _colorTablePaths.back());
|
||||
_colorTablePath = _colorTablePaths[0];
|
||||
_colorTableRanges.resize(nExtraQuantities, _colorTableRanges.back());
|
||||
_maskingRanges.resize(nExtraQuantities, _maskingRanges.back());
|
||||
}
|
||||
@@ -641,7 +673,6 @@ void RenderableFieldlinesSequence::setupProperties() {
|
||||
// Set defaults
|
||||
_colorQuantity = _colorQuantityTemp;
|
||||
_colorQuantityMinMax = _colorTableRanges[_colorQuantity];
|
||||
_colorTablePath = _colorTablePaths[0];
|
||||
|
||||
_maskingQuantity = _maskingQuantityTemp;
|
||||
_maskingMinMax = _maskingRanges[_colorQuantity];
|
||||
@@ -660,7 +691,6 @@ void RenderableFieldlinesSequence::definePropertyCallbackFunctions() {
|
||||
|
||||
_colorTablePath.onChange([this]() {
|
||||
_transferFunction->setPath(_colorTablePath);
|
||||
_colorTablePaths[_colorQuantity] = _colorTablePath;
|
||||
});
|
||||
|
||||
_colorQuantityMinMax.onChange([this]() {
|
||||
@@ -800,7 +830,6 @@ bool RenderableFieldlinesSequence::getStatesFromCdfFiles() {
|
||||
std::unordered_map<std::string, std::vector<glm::vec3>>
|
||||
extractSeedPointsFromFiles(std::filesystem::path filePath)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
std::unordered_map<std::string, std::vector<glm::vec3>> outMap;
|
||||
|
||||
if (!std::filesystem::is_directory(filePath)) {
|
||||
@@ -819,7 +848,7 @@ std::unordered_map<std::string, std::vector<glm::vec3>>
|
||||
continue;
|
||||
}
|
||||
|
||||
std::ifstream seedFile(spFile.path());
|
||||
std::ifstream seedFile(seedFilePath);
|
||||
if (!seedFile.good()) {
|
||||
LERROR(fmt::format("Could not open seed points file '{}'", seedFilePath));
|
||||
outMap.clear();
|
||||
@@ -848,7 +877,7 @@ std::unordered_map<std::string, std::vector<glm::vec3>>
|
||||
std::string name = seedFilePath.substr(0, lastIndex); // remove file extention
|
||||
size_t dateAndTimeSeperator = name.find_last_of('_');
|
||||
std::string time = name.substr(dateAndTimeSeperator + 1, name.length());
|
||||
std::string date = name.substr(dateAndTimeSeperator - 8, 8); //8 for yyyymmdd
|
||||
std::string date = name.substr(dateAndTimeSeperator - 8, 8); // 8 for yyyymmdd
|
||||
std::string dateAndTime = date + time;
|
||||
|
||||
// add outVec as value and time stamp as int as key
|
||||
@@ -953,10 +982,7 @@ void RenderableFieldlinesSequence::render(const RenderData& data, RendererTasks&
|
||||
textureUnit.activate();
|
||||
_transferFunction->bind(); // Calls update internally
|
||||
_shaderProgram->setUniform("colorTable", textureUnit);
|
||||
_shaderProgram->setUniform(
|
||||
"colorTableRange",
|
||||
_colorTableRanges[_colorQuantity]
|
||||
);
|
||||
_shaderProgram->setUniform("colorTableRange", _colorTableRanges[_colorQuantity]);
|
||||
}
|
||||
|
||||
if (_maskingEnabled) {
|
||||
@@ -994,7 +1020,7 @@ void RenderableFieldlinesSequence::render(const RenderData& data, RendererTasks&
|
||||
#endif
|
||||
|
||||
glMultiDrawArrays(
|
||||
GL_LINE_STRIP, //_drawingOutputType,
|
||||
GL_LINE_STRIP,
|
||||
_states[_activeStateIndex].lineStart().data(),
|
||||
_states[_activeStateIndex].lineCount().data(),
|
||||
static_cast<GLsizei>(_states[_activeStateIndex].lineStart().size())
|
||||
@@ -1023,7 +1049,7 @@ void RenderableFieldlinesSequence::update(const UpdateData& data) {
|
||||
const double currentTime = data.time.j2000Seconds();
|
||||
const bool isInInterval = (currentTime >= _startTimes[0]) &&
|
||||
(currentTime < _sequenceEndTime);
|
||||
|
||||
|
||||
// Check if current time in OpenSpace is within sequence interval
|
||||
if (isInInterval) {
|
||||
const size_t nextIdx = _activeTriggerTimeIndex + 1;
|
||||
@@ -1046,9 +1072,18 @@ void RenderableFieldlinesSequence::update(const UpdateData& data) {
|
||||
}
|
||||
} // else {we're still in same state as previous frame (no changes needed)}
|
||||
}
|
||||
// if only one state
|
||||
else if (_nStates == 1) {
|
||||
_activeTriggerTimeIndex = 0;
|
||||
_activeStateIndex = 0;
|
||||
if (!_hasBeenUpdated) {
|
||||
updateVertexPositionBuffer();
|
||||
}
|
||||
_hasBeenUpdated = true;
|
||||
}
|
||||
else {
|
||||
// Not in interval => set everything to false
|
||||
_activeTriggerTimeIndex = -1;
|
||||
_activeTriggerTimeIndex = -1;
|
||||
mustLoadNewStateFromDisk = false;
|
||||
needUpdate = false;
|
||||
}
|
||||
@@ -1082,14 +1117,16 @@ void RenderableFieldlinesSequence::update(const UpdateData& data) {
|
||||
_newStateIsReady = false;
|
||||
}
|
||||
|
||||
if (_shouldUpdateColorBuffer) {
|
||||
updateVertexColorBuffer();
|
||||
_shouldUpdateColorBuffer = false;
|
||||
}
|
||||
if (_colorMethod == 1) { //By quantity
|
||||
if (_shouldUpdateColorBuffer) {
|
||||
updateVertexColorBuffer();
|
||||
_shouldUpdateColorBuffer = false;
|
||||
}
|
||||
|
||||
if (_shouldUpdateMaskingBuffer) {
|
||||
updateVertexMaskingBuffer();
|
||||
_shouldUpdateMaskingBuffer = false;
|
||||
if (_shouldUpdateMaskingBuffer) {
|
||||
updateVertexMaskingBuffer();
|
||||
_shouldUpdateMaskingBuffer = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1109,6 +1146,9 @@ void RenderableFieldlinesSequence::updateActiveTriggerTimeIndex(double currentTi
|
||||
else {
|
||||
_activeTriggerTimeIndex = static_cast<int>(_nStates) - 1;
|
||||
}
|
||||
if (_nStates == 1) {
|
||||
_activeTriggerTimeIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Reading state from disk. Must be thread safe
|
||||
@@ -1127,6 +1167,7 @@ void unbindGL() {
|
||||
}
|
||||
|
||||
void RenderableFieldlinesSequence::updateVertexPositionBuffer() {
|
||||
if (_activeStateIndex == -1) { return; }
|
||||
glBindVertexArray(_vertexArrayObject);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer);
|
||||
|
||||
@@ -1146,6 +1187,7 @@ void RenderableFieldlinesSequence::updateVertexPositionBuffer() {
|
||||
}
|
||||
|
||||
void RenderableFieldlinesSequence::updateVertexColorBuffer() {
|
||||
if (_activeStateIndex == -1) { return; }
|
||||
glBindVertexArray(_vertexArrayObject);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertexColorBuffer);
|
||||
|
||||
@@ -1171,6 +1213,7 @@ void RenderableFieldlinesSequence::updateVertexColorBuffer() {
|
||||
}
|
||||
|
||||
void RenderableFieldlinesSequence::updateVertexMaskingBuffer() {
|
||||
if (_activeStateIndex == -1) { return; }
|
||||
glBindVertexArray(_vertexArrayObject);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertexMaskingBuffer);
|
||||
|
||||
|
||||
@@ -92,7 +92,6 @@ private:
|
||||
std::filesystem::path _seedPointDirectory;
|
||||
// optional except when using json input
|
||||
std::string _modelStr;
|
||||
fls::Model thismodel;
|
||||
|
||||
// Used for 'runtime-states'. True when loading a new state from disk on another
|
||||
// thread.
|
||||
@@ -108,6 +107,10 @@ private:
|
||||
// True when new state is loaded or user change which quantity used for masking out
|
||||
// line segments
|
||||
bool _shouldUpdateMaskingBuffer = false;
|
||||
// note Elon: rework the case of only one state
|
||||
// hasBeenUpdated only gets sets once, first iteration of update function, to
|
||||
// guarantee the vertext position buffer to be initialized.
|
||||
bool _hasBeenUpdated = false;
|
||||
|
||||
// Active index of _states. If(==-1)=>no state available for current time. Always the
|
||||
// same as _activeTriggerTimeIndex if(_loadingStatesDynamically==true), else
|
||||
|
||||
@@ -54,8 +54,8 @@ uniform vec2 domainLimR;
|
||||
|
||||
// Inputs
|
||||
layout(location = 0) in vec3 in_position; // Should be provided in meters
|
||||
layout(location = 1) in float in_color_scalar; // The extra value used to color lines. Location must correspond to _VA_COLOR in renderablefieldlinessequence.h
|
||||
layout(location = 2) in float in_masking_scalar; // The extra value used to mask out parts of lines. Location must correspond to _VA_MASKING in renderablefieldlinessequence.h
|
||||
layout(location = 1) in float in_color_scalar; // The extra value used to color lines.
|
||||
layout(location = 2) in float in_masking_scalar; // The extra value used to mask out parts of lines.
|
||||
|
||||
// These should correspond to the enum 'ColorMethod' in renderablefieldlinesequence.cpp
|
||||
const int uniformColor = 0;
|
||||
|
||||
@@ -546,7 +546,7 @@ std::vector<float> FitsFileReader::readSpeckFile(const std::filesystem::path& fi
|
||||
std::streampos position = fileStream.tellg();
|
||||
std::getline(fileStream, line);
|
||||
|
||||
if (line[0] == '#' || line.empty()) {
|
||||
if (line.empty() || line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
namespace openspace::gaia {
|
||||
|
||||
enum RenderOption {
|
||||
enum RenderMode {
|
||||
Static = 0,
|
||||
Color = 1,
|
||||
Motion = 2
|
||||
|
||||
@@ -395,7 +395,7 @@ void OctreeManager::findAndFetchNeighborNode(unsigned long long firstParentId, i
|
||||
std::map<int, std::vector<float>> OctreeManager::traverseData(const glm::dmat4& mvp,
|
||||
const glm::vec2& screenSize,
|
||||
int& deltaStars,
|
||||
gaia::RenderOption option,
|
||||
gaia::RenderMode mode,
|
||||
float lodPixelThreshold)
|
||||
{
|
||||
std::map<int, std::vector<float>> renderData;
|
||||
@@ -471,7 +471,7 @@ std::map<int, std::vector<float>> OctreeManager::traverseData(const glm::dmat4&
|
||||
mvp,
|
||||
screenSize,
|
||||
deltaStars,
|
||||
option
|
||||
mode
|
||||
);
|
||||
|
||||
// Avoid freezing when switching render mode for large datasets by only fetching
|
||||
@@ -521,11 +521,11 @@ std::map<int, std::vector<float>> OctreeManager::traverseData(const glm::dmat4&
|
||||
return renderData;
|
||||
}
|
||||
|
||||
std::vector<float> OctreeManager::getAllData(gaia::RenderOption option) {
|
||||
std::vector<float> OctreeManager::getAllData(gaia::RenderMode mode) {
|
||||
std::vector<float> fullData;
|
||||
|
||||
for (size_t i = 0; i < 8; ++i) {
|
||||
std::vector<float> tmpData = getNodeData(*_root->Children[i], option);
|
||||
std::vector<float> tmpData = getNodeData(*_root->Children[i], mode);
|
||||
fullData.insert(fullData.end(), tmpData.begin(), tmpData.end());
|
||||
}
|
||||
return fullData;
|
||||
@@ -1037,7 +1037,7 @@ void OctreeManager::sliceNodeLodCache(OctreeNode& node) {
|
||||
std::vector<float> tmpCol;
|
||||
std::vector<float> tmpVel;
|
||||
// Ordered map contain the MAX_STARS_PER_NODE brightest stars in all children!
|
||||
for (auto const &[absMag, placement] : node.magOrder) {
|
||||
for (auto const& [absMag, placement] : node.magOrder) {
|
||||
auto posBegin = node.posData.begin() + placement * POS_SIZE;
|
||||
auto colBegin = node.colData.begin() + placement * COL_SIZE;
|
||||
auto velBegin = node.velData.begin() + placement * VEL_SIZE;
|
||||
@@ -1102,7 +1102,7 @@ std::map<int, std::vector<float>> OctreeManager::checkNodeIntersection(OctreeNod
|
||||
const glm::dmat4& mvp,
|
||||
const glm::vec2& screenSize,
|
||||
int& deltaStars,
|
||||
gaia::RenderOption option)
|
||||
gaia::RenderMode mode)
|
||||
{
|
||||
std::map<int, std::vector<float>> fetchedData;
|
||||
//int depth = static_cast<int>(log2( MAX_DIST / node->halfDimension ));
|
||||
@@ -1172,7 +1172,7 @@ std::map<int, std::vector<float>> OctreeManager::checkNodeIntersection(OctreeNod
|
||||
// Insert data and adjust stars added in this frame.
|
||||
fetchedData[node.bufferIndex] = constructInsertData(
|
||||
node,
|
||||
option,
|
||||
mode,
|
||||
deltaStars
|
||||
);
|
||||
}
|
||||
@@ -1191,7 +1191,7 @@ std::map<int, std::vector<float>> OctreeManager::checkNodeIntersection(OctreeNod
|
||||
// Insert data and adjust stars added in this frame.
|
||||
fetchedData[node.bufferIndex] = constructInsertData(
|
||||
node,
|
||||
option,
|
||||
mode,
|
||||
deltaStars
|
||||
);
|
||||
}
|
||||
@@ -1211,7 +1211,7 @@ std::map<int, std::vector<float>> OctreeManager::checkNodeIntersection(OctreeNod
|
||||
mvp,
|
||||
screenSize,
|
||||
deltaStars,
|
||||
option
|
||||
mode
|
||||
);
|
||||
fetchedData.insert(tmpData.begin(), tmpData.end());
|
||||
}
|
||||
@@ -1255,18 +1255,18 @@ std::map<int, std::vector<float>> OctreeManager::removeNodeFromCache(OctreeNode&
|
||||
}
|
||||
|
||||
std::vector<float> OctreeManager::getNodeData(const OctreeNode& node,
|
||||
gaia::RenderOption option)
|
||||
gaia::RenderMode mode)
|
||||
{
|
||||
// Return node data if node is a leaf.
|
||||
if (node.isLeaf) {
|
||||
int dStars = 0;
|
||||
return constructInsertData(node, option, dStars);
|
||||
return constructInsertData(node, mode, dStars);
|
||||
}
|
||||
|
||||
// If we're not in a leaf, get data from all children recursively.
|
||||
std::vector<float> nodeData;
|
||||
for (size_t i = 0; i < 8; ++i) {
|
||||
std::vector<float> tmpData = getNodeData(*node.Children[i], option);
|
||||
std::vector<float> tmpData = getNodeData(*node.Children[i], mode);
|
||||
nodeData.insert(nodeData.end(), tmpData.begin(), tmpData.end());
|
||||
}
|
||||
return nodeData;
|
||||
@@ -1362,7 +1362,7 @@ bool OctreeManager::updateBufferIndex(OctreeNode& node) {
|
||||
}
|
||||
|
||||
std::vector<float> OctreeManager::constructInsertData(const OctreeNode& node,
|
||||
gaia::RenderOption option,
|
||||
gaia::RenderMode mode,
|
||||
int& deltaStars)
|
||||
{
|
||||
// Return early if node doesn't contain any stars!
|
||||
@@ -1376,12 +1376,12 @@ std::vector<float> OctreeManager::constructInsertData(const OctreeNode& node,
|
||||
if (_useVBO) {
|
||||
insertData.resize(POS_SIZE * MAX_STARS_PER_NODE, 0.f);
|
||||
}
|
||||
if (option != gaia::RenderOption::Static) {
|
||||
if (mode != gaia::RenderMode::Static) {
|
||||
insertData.insert(insertData.end(), node.colData.begin(), node.colData.end());
|
||||
if (_useVBO) {
|
||||
insertData.resize((POS_SIZE + COL_SIZE) * MAX_STARS_PER_NODE, 0.f);
|
||||
}
|
||||
if (option == gaia::RenderOption::Motion) {
|
||||
if (mode == gaia::RenderMode::Motion) {
|
||||
insertData.insert(insertData.end(), node.velData.begin(), node.velData.end());
|
||||
if (_useVBO) {
|
||||
insertData.resize(
|
||||
|
||||
@@ -119,13 +119,13 @@ public:
|
||||
* call.
|
||||
*/
|
||||
std::map<int, std::vector<float>> traverseData(const glm::dmat4& mvp,
|
||||
const glm::vec2& screenSize, int& deltaStars, gaia::RenderOption option,
|
||||
const glm::vec2& screenSize, int& deltaStars, gaia::RenderMode mode,
|
||||
float lodPixelThreshold);
|
||||
|
||||
/**
|
||||
* Builds full render data structure by traversing all leaves in the Octree.
|
||||
*/
|
||||
std::vector<float> getAllData(gaia::RenderOption option);
|
||||
std::vector<float> getAllData(gaia::RenderMode mode);
|
||||
|
||||
/**
|
||||
* Removes all data from Octree, or only from a specific branch if specified.
|
||||
@@ -244,7 +244,7 @@ private:
|
||||
*/
|
||||
std::map<int, std::vector<float>> checkNodeIntersection(OctreeNode& node,
|
||||
const glm::dmat4& mvp, const glm::vec2& screenSize, int& deltaStars,
|
||||
gaia::RenderOption option);
|
||||
gaia::RenderMode mode);
|
||||
|
||||
/**
|
||||
* Checks if specified node existed in cache, and removes it if that's the case.
|
||||
@@ -258,7 +258,7 @@ private:
|
||||
/**
|
||||
* Get data in node and its descendants regardless if they are visible or not.
|
||||
*/
|
||||
std::vector<float> getNodeData(const OctreeNode& node, gaia::RenderOption option);
|
||||
std::vector<float> getNodeData(const OctreeNode& node, gaia::RenderMode mode);
|
||||
|
||||
/**
|
||||
* Clear data from node and its descendants and shrink vectors to deallocate memory.
|
||||
@@ -285,7 +285,7 @@ private:
|
||||
* \param deltaStars keeps track of how many stars that were added.
|
||||
*/
|
||||
std::vector<float> constructInsertData(const OctreeNode& node,
|
||||
gaia::RenderOption option, int& deltaStars);
|
||||
gaia::RenderMode mode, int& deltaStars);
|
||||
|
||||
/**
|
||||
* Write a node to outFileStream. \param writeData defines if data should be included
|
||||
|
||||
@@ -73,9 +73,9 @@ namespace {
|
||||
"option is suited for bigger datasets.)"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo RenderOptionInfo = {
|
||||
"RenderOption",
|
||||
"Render Option",
|
||||
constexpr openspace::properties::Property::PropertyInfo RenderModeInfo = {
|
||||
"RenderMode",
|
||||
"Render Mode",
|
||||
"This value determines which predefined columns to use in rendering. If "
|
||||
"'Static' only the position of the stars is used. 'Color' uses position + color "
|
||||
"parameters and 'Motion' uses pos, color as well as velocity for the stars."
|
||||
@@ -315,13 +315,13 @@ namespace {
|
||||
// [[codegen::verbatim(FileReaderOptionInfo.description)]]
|
||||
FileReader fileReaderOption;
|
||||
|
||||
enum class [[codegen::map(openspace::gaia::RenderOption)]] RenderOption {
|
||||
enum class [[codegen::map(openspace::gaia::RenderMode)]] RenderMode {
|
||||
Static,
|
||||
Color,
|
||||
Motion
|
||||
};
|
||||
// [[codegen::verbatim(RenderOptionInfo.description)]]
|
||||
std::optional<RenderOption> renderOption;
|
||||
// [[codegen::verbatim(RenderModeInfo.description)]]
|
||||
std::optional<RenderMode> renderMode;
|
||||
|
||||
enum class [[codegen::map(openspace::gaia::ShaderOption)]] ShaderOption {
|
||||
PointSSBO [[codegen::key("Point_SSBO")]],
|
||||
@@ -446,7 +446,7 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary)
|
||||
FileReaderOptionInfo,
|
||||
properties::OptionProperty::DisplayType::Dropdown
|
||||
)
|
||||
, _renderOption(RenderOptionInfo, properties::OptionProperty::DisplayType::Dropdown)
|
||||
, _renderMode(RenderModeInfo, properties::OptionProperty::DisplayType::Dropdown)
|
||||
, _shaderOption(ShaderOptionInfo, properties::OptionProperty::DisplayType::Dropdown)
|
||||
, _nRenderedStars(NumRenderedStarsInfo, 0, 0, 2000000000) // 2 Billion stars
|
||||
, _cpuRamBudgetProperty(CpuRamBudgetInfo, 0.f, 0.f, 1.f)
|
||||
@@ -464,7 +464,14 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary)
|
||||
_dataFile = std::make_unique<File>(_filePath.value());
|
||||
_dataFile->setCallback([this]() { _dataIsDirty = true; });
|
||||
|
||||
_filePath.onChange([this]() { _dataIsDirty = true; });
|
||||
_filePath.onChange([this]() {
|
||||
if (std::filesystem::exists(_filePath.value())) {
|
||||
_dataIsDirty = true;
|
||||
}
|
||||
else {
|
||||
LWARNING(fmt::format("File not found: {}", _filePath));
|
||||
}
|
||||
});
|
||||
addProperty(_filePath);
|
||||
|
||||
_fileReaderOption.addOptions({
|
||||
@@ -476,16 +483,16 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary)
|
||||
});
|
||||
_fileReaderOption = codegen::map<gaia::FileReaderOption>(p.fileReaderOption);
|
||||
|
||||
_renderOption.addOptions({
|
||||
{ gaia::RenderOption::Static, "Static" },
|
||||
{ gaia::RenderOption::Color, "Color" },
|
||||
{ gaia::RenderOption::Motion, "Motion" }
|
||||
_renderMode.addOptions({
|
||||
{ gaia::RenderMode::Static, "Static" },
|
||||
{ gaia::RenderMode::Color, "Color" },
|
||||
{ gaia::RenderMode::Motion, "Motion" }
|
||||
});
|
||||
if (p.renderOption.has_value()) {
|
||||
_renderOption = codegen::map<gaia::RenderOption>(*p.renderOption);
|
||||
if (p.renderMode.has_value()) {
|
||||
_renderMode = codegen::map<gaia::RenderMode>(*p.renderMode);
|
||||
}
|
||||
_renderOption.onChange([&]() { _buffersAreDirty = true; });
|
||||
addProperty(_renderOption);
|
||||
_renderMode.onChange([&]() { _buffersAreDirty = true; });
|
||||
addProperty(_renderMode);
|
||||
|
||||
_shaderOption.addOptions({
|
||||
{ gaia::ShaderOption::PointSSBO, "Point_SSBO" },
|
||||
@@ -952,13 +959,13 @@ void RenderableGaiaStars::render(const RenderData& data, RendererTasks&) {
|
||||
}
|
||||
|
||||
// Traverse Octree and build a map with new nodes to render, uses mvp matrix to decide
|
||||
const int renderOption = _renderOption;
|
||||
const int renderOption = _renderMode;
|
||||
int deltaStars = 0;
|
||||
std::map<int, std::vector<float>> updateData = _octreeManager.traverseData(
|
||||
modelViewProjMat,
|
||||
screenSize,
|
||||
deltaStars,
|
||||
gaia::RenderOption(renderOption),
|
||||
gaia::RenderMode(renderOption),
|
||||
_lodPixelThreshold
|
||||
);
|
||||
|
||||
@@ -1026,7 +1033,7 @@ void RenderableGaiaStars::render(const RenderData& data, RendererTasks&) {
|
||||
|
||||
// Update SSBO with one insert per chunk/node.
|
||||
// The key in map holds the offset index.
|
||||
for (const auto &[offset, subData] : updateData) {
|
||||
for (const auto& [offset, subData] : updateData) {
|
||||
// We don't need to fill chunk with zeros for SSBOs!
|
||||
// Just check if we have any values to update.
|
||||
if (!subData.empty()) {
|
||||
@@ -1081,7 +1088,7 @@ void RenderableGaiaStars::render(const RenderData& data, RendererTasks&) {
|
||||
}
|
||||
|
||||
// Update Color VBO if render option is 'Color' or 'Motion'.
|
||||
if (renderOption != gaia::RenderOption::Static) {
|
||||
if (renderOption != gaia::RenderMode::Static) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboCol);
|
||||
float colMemoryShare = static_cast<float>(ColorSize) / _nRenderValuesPerStar;
|
||||
size_t colChunkSize = maxStarsPerNode * ColorSize;
|
||||
@@ -1112,7 +1119,7 @@ void RenderableGaiaStars::render(const RenderData& data, RendererTasks&) {
|
||||
}
|
||||
|
||||
// Update Velocity VBO if specified.
|
||||
if (renderOption == gaia::RenderOption::Motion) {
|
||||
if (renderOption == gaia::RenderMode::Motion) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVel);
|
||||
float velMemoryShare = static_cast<float>(VelocitySize) /
|
||||
_nRenderValuesPerStar;
|
||||
@@ -1163,7 +1170,7 @@ void RenderableGaiaStars::render(const RenderData& data, RendererTasks&) {
|
||||
_uniformCache.time,
|
||||
static_cast<float>(data.time.j2000Seconds())
|
||||
);
|
||||
_program->setUniform(_uniformCache.renderOption, _renderOption);
|
||||
_program->setUniform(_uniformCache.renderOption, _renderMode);
|
||||
_program->setUniform(_uniformCache.viewScaling, viewScaling);
|
||||
_program->setUniform(_uniformCache.cutOffThreshold, _cutOffThreshold);
|
||||
_program->setUniform(_uniformCache.luminosityMultiplier, _luminosityMultiplier);
|
||||
@@ -1340,7 +1347,7 @@ void RenderableGaiaStars::checkGlErrors(const std::string& identifier) const {
|
||||
|
||||
void RenderableGaiaStars::update(const UpdateData&) {
|
||||
const int shaderOption = _shaderOption;
|
||||
const int renderOption = _renderOption;
|
||||
const int renderOption = _renderMode;
|
||||
|
||||
// Don't update anything if we are in the middle of a rebuild.
|
||||
if (_octreeManager.isRebuildOngoing()) {
|
||||
@@ -1675,10 +1682,10 @@ void RenderableGaiaStars::update(const UpdateData&) {
|
||||
LDEBUG("Regenerating buffers");
|
||||
|
||||
// Set values per star slice depending on render option.
|
||||
if (renderOption == gaia::RenderOption::Static) {
|
||||
if (renderOption == gaia::RenderMode::Static) {
|
||||
_nRenderValuesPerStar = PositionSize;
|
||||
}
|
||||
else if (renderOption == gaia::RenderOption::Color) {
|
||||
else if (renderOption == gaia::RenderMode::Color) {
|
||||
_nRenderValuesPerStar = PositionSize + ColorSize;
|
||||
}
|
||||
else { // (renderOption == gaia::RenderOption::Motion)
|
||||
@@ -1847,7 +1854,7 @@ void RenderableGaiaStars::update(const UpdateData&) {
|
||||
glBindVertexArray(_vao);
|
||||
|
||||
switch (renderOption) {
|
||||
case gaia::RenderOption::Static: {
|
||||
case gaia::RenderMode::Static: {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboPos);
|
||||
GLint positionAttrib = _program->attributeLocation("in_position");
|
||||
glEnableVertexAttribArray(positionAttrib);
|
||||
@@ -1863,7 +1870,7 @@ void RenderableGaiaStars::update(const UpdateData&) {
|
||||
|
||||
break;
|
||||
}
|
||||
case gaia::RenderOption::Color: {
|
||||
case gaia::RenderMode::Color: {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboPos);
|
||||
GLint positionAttrib = _program->attributeLocation("in_position");
|
||||
glEnableVertexAttribArray(positionAttrib);
|
||||
@@ -1891,7 +1898,7 @@ void RenderableGaiaStars::update(const UpdateData&) {
|
||||
);
|
||||
break;
|
||||
}
|
||||
case gaia::RenderOption::Motion: {
|
||||
case gaia::RenderMode::Motion: {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboPos);
|
||||
GLint positionAttrib = _program->attributeLocation("in_position");
|
||||
glEnableVertexAttribArray(positionAttrib);
|
||||
|
||||
@@ -155,7 +155,7 @@ private:
|
||||
properties::StringListProperty _columnNamesList;
|
||||
std::vector<std::string> _columnNames;
|
||||
properties::OptionProperty _fileReaderOption;
|
||||
properties::OptionProperty _renderOption;
|
||||
properties::OptionProperty _renderMode;
|
||||
properties::OptionProperty _shaderOption;
|
||||
properties::IntProperty _nRenderedStars;
|
||||
// LongLongProperty doesn't show up in menu, use FloatProperty instead.
|
||||
|
||||
@@ -49,7 +49,9 @@ documentation::Documentation SpoutImageProvider::Documentation() {
|
||||
return codegen::doc<Parameters>("globebrowsing_spoutimageprovider");
|
||||
}
|
||||
|
||||
SpoutImageProvider::SpoutImageProvider(const ghoul::Dictionary& dictionary) {
|
||||
SpoutImageProvider::SpoutImageProvider(
|
||||
[[maybe_unused]] const ghoul::Dictionary& dictionary)
|
||||
{
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_SPOUT
|
||||
|
||||
@@ -505,6 +505,13 @@ TemporalTileProvider::tileProvider<TemporalTileProvider::Mode::Folder, true>(
|
||||
|
||||
It curr = next != _folder.files.begin() ? next - 1 : next;
|
||||
It nextNext = next != _folder.files.end() ? next + 1 : curr;
|
||||
|
||||
if (next == _folder.files.end()) {
|
||||
curr = _folder.files.end() - 1;
|
||||
next = curr;
|
||||
nextNext = curr;
|
||||
}
|
||||
|
||||
It prev = curr != _folder.files.begin() ? curr - 1 : curr;
|
||||
|
||||
_interpolateTileProvider->t1 = retrieveTileProvider(Time(curr->first));
|
||||
@@ -512,14 +519,11 @@ TemporalTileProvider::tileProvider<TemporalTileProvider::Mode::Folder, true>(
|
||||
_interpolateTileProvider->future = retrieveTileProvider(Time(nextNext->first));
|
||||
_interpolateTileProvider->before = retrieveTileProvider(Time(prev->first));
|
||||
|
||||
_interpolateTileProvider->factor = static_cast<float>(
|
||||
(time.j2000Seconds() - curr->first) /
|
||||
(next->first - curr->first)
|
||||
float factor = static_cast<float>(
|
||||
(time.j2000Seconds() - curr->first) / (next->first - curr->first)
|
||||
);
|
||||
|
||||
if (_interpolateTileProvider->factor > 1.f) {
|
||||
_interpolateTileProvider->factor = 1.f;
|
||||
}
|
||||
_interpolateTileProvider->factor = std::clamp(factor, 0.f, 1.f);
|
||||
|
||||
return _interpolateTileProvider.get();
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace openspace::globebrowsing {
|
||||
*/
|
||||
class RangedTime {
|
||||
public:
|
||||
RangedTime() {};
|
||||
RangedTime() {}
|
||||
|
||||
/*
|
||||
* Constructor that accepts an ISO8601 date/time string (YYYY-MM-DDTHH:mm:ss) for an
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
|
||||
|
||||
set(HEADER_FILES
|
||||
include/gui.h
|
||||
include/guiactioncomponent.h
|
||||
include/guicomponent.h
|
||||
include/guifilepathcomponent.h
|
||||
@@ -37,15 +36,14 @@ set(HEADER_FILES
|
||||
include/guimissioncomponent.h
|
||||
include/guiparallelcomponent.h
|
||||
include/guipropertycomponent.h
|
||||
include/guiscenecomponent.h
|
||||
include/guispacetimecomponent.h
|
||||
include/guiiswacomponent.h
|
||||
include/imgui_include.h
|
||||
include/renderproperties.h
|
||||
)
|
||||
source_group("Header Files" FILES ${HEADER_FILES})
|
||||
|
||||
set(SOURCE_FILES
|
||||
src/gui.cpp
|
||||
src/guiactioncomponent.cpp
|
||||
src/guicomponent.cpp
|
||||
src/guifilepathcomponent.cpp
|
||||
@@ -57,8 +55,8 @@ set(SOURCE_FILES
|
||||
src/guimissioncomponent.cpp
|
||||
src/guiparallelcomponent.cpp
|
||||
src/guipropertycomponent.cpp
|
||||
src/guiscenecomponent.cpp
|
||||
src/guispacetimecomponent.cpp
|
||||
src/guiiswacomponent.cpp
|
||||
src/renderproperties.cpp
|
||||
)
|
||||
source_group("Source Files" FILES ${SOURCE_FILES})
|
||||
|
||||
@@ -24,10 +24,11 @@
|
||||
|
||||
#include <modules/imgui/imguimodule.h>
|
||||
|
||||
#include <modules/imgui/include/imgui_include.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/globalscallbacks.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/interaction/sessionrecording.h>
|
||||
#include <openspace/navigation/navigationhandler.h>
|
||||
#include <openspace/network/parallelpeer.h>
|
||||
@@ -35,136 +36,183 @@
|
||||
#include <openspace/rendering/luaconsole.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/profiling.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <ghoul/filesystem/cachemanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/opengl/textureunit.h>
|
||||
|
||||
// #define SHOW_IMGUI_HELPERS
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "GUI";
|
||||
constexpr const char* GuiFont = "${FONTS}/arimo/Arimo-Regular.ttf";
|
||||
constexpr const float FontSize = 14.f;
|
||||
|
||||
ImFont* captionFont = nullptr;
|
||||
|
||||
constexpr const std::array<const char*, 2> UniformNames = { "tex", "ortho" };
|
||||
|
||||
void addScreenSpaceRenderableLocal(std::string identifier, std::string texturePath) {
|
||||
if (!std::filesystem::is_regular_file(absPath(texturePath))) {
|
||||
LWARNING(fmt::format("Could not find image '{}'", texturePath));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string script;
|
||||
if (identifier.empty()) {
|
||||
script = fmt::format(
|
||||
"openspace.addScreenSpaceRenderable({{\
|
||||
Type = 'ScreenSpaceImageLocal',\
|
||||
TexturePath = openspace.absPath('{}')\
|
||||
}});",
|
||||
texturePath
|
||||
);
|
||||
}
|
||||
else {
|
||||
script = fmt::format(
|
||||
"openspace.addScreenSpaceRenderable({{\
|
||||
Type = 'ScreenSpaceImageLocal',\
|
||||
TexturePath = openspace.absPath('{0}'),\
|
||||
Identifier = '{1}',\
|
||||
Name = '{1}'\
|
||||
}});",
|
||||
texturePath, identifier
|
||||
);
|
||||
}
|
||||
|
||||
openspace::global::scriptEngine->queueScript(
|
||||
script,
|
||||
openspace::scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
|
||||
void addScreenSpaceRenderableOnline(std::string identifier, std::string texturePath) {
|
||||
std::string script;
|
||||
if (identifier.empty()) {
|
||||
script = fmt::format(
|
||||
"openspace.addScreenSpaceRenderable({{\
|
||||
Type = 'ScreenSpaceImageOnline',\
|
||||
URL = '{}'\
|
||||
}});",
|
||||
texturePath
|
||||
);
|
||||
}
|
||||
else {
|
||||
script = fmt::format(
|
||||
"openspace.addScreenSpaceRenderable({{\
|
||||
Type = 'ScreenSpaceImageOnline',\
|
||||
URL = '{0}',\
|
||||
Identifier = '{1}',\
|
||||
Name = '{1}'\
|
||||
}});",
|
||||
texturePath,
|
||||
identifier
|
||||
);
|
||||
}
|
||||
|
||||
openspace::global::scriptEngine->queueScript(
|
||||
script,
|
||||
openspace::scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo EnabledInfo = {
|
||||
"Enabled",
|
||||
"Is Enabled",
|
||||
"This setting determines whether this object will be visible or not."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo CollapsedInfo = {
|
||||
"Collapsed",
|
||||
"Is Collapsed",
|
||||
"This setting determines whether this window is collapsed or not."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ShowHelpInfo = {
|
||||
"ShowHelpText",
|
||||
"Show tooltip help",
|
||||
"If this value is enabled these kinds of tooltips are shown for most properties "
|
||||
"explaining what impact they have on the visuals."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo HelpTextDelayInfo = {
|
||||
"HelpTextDelay",
|
||||
"Tooltip Delay (in s)",
|
||||
"This value determines the delay in seconds after which the tooltip is shown."
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) {
|
||||
addPropertySubOwner(gui);
|
||||
void CaptionText(const char* text) {
|
||||
ImGui::PushFont(captionFont);
|
||||
ImGui::Text("%s", text);
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
global::callback::initialize->emplace_back([&]() {
|
||||
LDEBUGC("ImGUIModule", "Initializing GUI");
|
||||
gui.initialize();
|
||||
ImGUIModule::ImGUIModule()
|
||||
: OpenSpaceModule(Name)
|
||||
, _isEnabled(EnabledInfo, false)
|
||||
, _isCollapsed(CollapsedInfo, false)
|
||||
, _sceneProperty("Scene", "Scene", gui::GuiPropertyComponent::UseTreeLayout::Yes)
|
||||
, _property("Settings", "Settings")
|
||||
, _showHelpText(ShowHelpInfo, true)
|
||||
, _helpTextDelay(HelpTextDelayInfo, 1.f, 0.f, 10.f)
|
||||
{
|
||||
addProperty(_isEnabled);
|
||||
addProperty(_isCollapsed);
|
||||
|
||||
gui._globalProperty.setSource(
|
||||
[]() {
|
||||
std::vector<properties::PropertyOwner*> res = {
|
||||
global::navigationHandler,
|
||||
global::sessionRecording,
|
||||
global::timeManager,
|
||||
global::renderEngine,
|
||||
global::parallelPeer,
|
||||
global::luaConsole,
|
||||
global::dashboard
|
||||
};
|
||||
return res;
|
||||
}
|
||||
);
|
||||
for (gui::GuiComponent* comp : _components) {
|
||||
addPropertySubOwner(comp);
|
||||
}
|
||||
_spaceTime.setEnabled(true);
|
||||
|
||||
gui._screenSpaceProperty.setSource(
|
||||
[]() {
|
||||
return global::screenSpaceRootPropertyOwner->propertySubOwners();
|
||||
{
|
||||
auto showHelpTextFunc = [this]() {
|
||||
for (gui::GuiComponent* comp : _components) {
|
||||
comp->setShowHelpTooltip(_showHelpText);
|
||||
}
|
||||
);
|
||||
};
|
||||
showHelpTextFunc();
|
||||
_showHelpText.onChange(std::move(showHelpTextFunc));
|
||||
addProperty(_showHelpText);
|
||||
}
|
||||
|
||||
gui._moduleProperty.setSource(
|
||||
[]() {
|
||||
std::vector<properties::PropertyOwner*> v;
|
||||
v.push_back(global::moduleEngine);
|
||||
return v;
|
||||
{
|
||||
auto helpTextDelayFunc = [this]() {
|
||||
for (gui::GuiComponent* comp : _components) {
|
||||
comp->setShowHelpTooltipDelay(_helpTextDelay);
|
||||
}
|
||||
);
|
||||
|
||||
gui._sceneProperty.setSource(
|
||||
[]() {
|
||||
const Scene* scene = global::renderEngine->scene();
|
||||
const std::vector<SceneGraphNode*>& nodes = scene ?
|
||||
scene->allSceneGraphNodes() :
|
||||
std::vector<SceneGraphNode*>();
|
||||
|
||||
return std::vector<properties::PropertyOwner*>(
|
||||
nodes.begin(),
|
||||
nodes.end()
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
gui._featuredProperties.setSource(
|
||||
[]() {
|
||||
std::vector<SceneGraphNode*> nodes =
|
||||
global::renderEngine->scene()->allSceneGraphNodes();
|
||||
|
||||
nodes.erase(
|
||||
std::remove_if(
|
||||
nodes.begin(),
|
||||
nodes.end(),
|
||||
[](SceneGraphNode* n) {
|
||||
const std::vector<std::string>& tags = n->tags();
|
||||
const auto it = std::find(
|
||||
tags.begin(),
|
||||
tags.end(),
|
||||
"GUI.Interesting"
|
||||
);
|
||||
return it == tags.end();
|
||||
}
|
||||
),
|
||||
nodes.end()
|
||||
);
|
||||
return std::vector<properties::PropertyOwner*>(
|
||||
nodes.begin(),
|
||||
nodes.end()
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
global::callback::deinitialize->emplace_back([&]() {
|
||||
ZoneScopedN("ImGUI")
|
||||
|
||||
LDEBUGC("ImGui", "Deinitialize GUI");
|
||||
gui.deinitialize();
|
||||
});
|
||||
|
||||
global::callback::initializeGL->emplace_back([&]() {
|
||||
ZoneScopedN("ImGUI")
|
||||
|
||||
LDEBUGC("ImGui", "Initializing GUI OpenGL");
|
||||
gui.initializeGL();
|
||||
});
|
||||
|
||||
global::callback::deinitializeGL->emplace_back([&]() {
|
||||
ZoneScopedN("ImGUI")
|
||||
|
||||
LDEBUGC("ImGui", "Deinitialize GUI OpenGL");
|
||||
gui.deinitializeGL();
|
||||
});
|
||||
};
|
||||
helpTextDelayFunc();
|
||||
_helpTextDelay.onChange(std::move(helpTextDelayFunc));
|
||||
addProperty(_helpTextDelay);
|
||||
}
|
||||
|
||||
global::callback::draw2D->emplace_back([&]() {
|
||||
ZoneScopedN("ImGUI")
|
||||
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
WindowDelegate& delegate = *global::windowDelegate;
|
||||
const bool showGui = delegate.hasGuiWindow() ? delegate.isGuiWindow() : true;
|
||||
if (delegate.isMaster() && showGui) {
|
||||
const glm::ivec2 windowSize = delegate.currentSubwindowSize();
|
||||
const glm::ivec2 resolution = delegate.currentDrawBufferResolution();
|
||||
|
||||
if (windowSize.x <= 0 || windowSize.y <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const glm::ivec2 resolution = delegate.currentDrawBufferResolution();
|
||||
const double dt = std::max(delegate.averageDeltaTime(), 0.0);
|
||||
// We don't do any collection of immediate mode user interface, so it
|
||||
// is fine to open and close a frame immediately
|
||||
gui.startFrame(
|
||||
renderFrame(
|
||||
static_cast<float>(dt),
|
||||
glm::vec2(windowSize),
|
||||
resolution / windowSize,
|
||||
_mousePosition,
|
||||
_mouseButtons
|
||||
);
|
||||
|
||||
gui.endFrame();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -172,13 +220,7 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) {
|
||||
[&](Key key, KeyModifier mod, KeyAction action) -> bool {
|
||||
ZoneScopedN("ImGUI")
|
||||
|
||||
// A list of all the windows that can show up by themselves
|
||||
if (gui.isEnabled() ||gui._sceneProperty.isEnabled()) {
|
||||
return gui.keyCallback(key, mod, action);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return _isEnabled ? keyCallback(key, mod, action) : false;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -186,13 +228,7 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) {
|
||||
[&](unsigned int codepoint, KeyModifier modifier) -> bool {
|
||||
ZoneScopedN("ImGUI")
|
||||
|
||||
// A list of all the windows that can show up by themselves
|
||||
if (gui.isEnabled() || gui._sceneProperty.isEnabled()) {
|
||||
return gui.charCallback(codepoint, modifier);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return _isEnabled ? charCallback(codepoint, modifier) : false;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -213,13 +249,7 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) {
|
||||
_mouseButtons &= ~(1 << static_cast<int>(button));
|
||||
}
|
||||
|
||||
// A list of all the windows that can show up by themselves
|
||||
if (gui.isEnabled() || gui._sceneProperty.isEnabled()) {
|
||||
return gui.mouseButtonCallback(button, action);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return _isEnabled ? mouseButtonCallback(button, action) : false;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -227,33 +257,575 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) {
|
||||
[&](double, double posY) -> bool {
|
||||
ZoneScopedN("ImGUI")
|
||||
|
||||
// A list of all the windows that can show up by themselves
|
||||
if (gui.isEnabled() || gui._sceneProperty.isEnabled()) {
|
||||
return gui.mouseWheelCallback(posY);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return _isEnabled ? mouseWheelCallback(posY) : false;
|
||||
}
|
||||
);
|
||||
|
||||
global::callback::touchDetected->emplace_back(
|
||||
[&](TouchInput input) -> bool {
|
||||
return gui.touchDetectedCallback(input);
|
||||
return touchDetectedCallback(input);
|
||||
}
|
||||
);
|
||||
|
||||
global::callback::touchUpdated->emplace_back(
|
||||
[&](TouchInput input) -> bool {
|
||||
return gui.touchUpdatedCallback(input);
|
||||
return touchUpdatedCallback(input);
|
||||
}
|
||||
);
|
||||
|
||||
global::callback::touchExit->emplace_back(
|
||||
[&](TouchInput input) {
|
||||
gui.touchExitCallback(input);
|
||||
touchExitCallback(input);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void ImGUIModule::internalInitialize(const ghoul::Dictionary&) {
|
||||
LDEBUGC("ImGUIModule", "Initializing GUI");
|
||||
|
||||
_sceneProperty.setPropertyOwnerFunction(
|
||||
[]() {
|
||||
const Scene* scene = global::renderEngine->scene();
|
||||
const std::vector<SceneGraphNode*>& nodes = scene ?
|
||||
scene->allSceneGraphNodes() :
|
||||
std::vector<SceneGraphNode*>();
|
||||
|
||||
return std::vector<properties::PropertyOwner*>(nodes.begin(), nodes.end());
|
||||
}
|
||||
);
|
||||
|
||||
_property.setPropertyOwners({
|
||||
global::screenSpaceRootPropertyOwner,
|
||||
global::moduleEngine,
|
||||
global::navigationHandler,
|
||||
global::sessionRecording,
|
||||
global::timeManager,
|
||||
global::renderEngine,
|
||||
global::parallelPeer,
|
||||
global::luaConsole,
|
||||
global::dashboard
|
||||
});
|
||||
}
|
||||
|
||||
void ImGUIModule::internalDeinitialize() {
|
||||
for (ImGuiContext* ctx : _contexts) {
|
||||
ImGui::DestroyContext(ctx);
|
||||
}
|
||||
|
||||
for (gui::GuiComponent* comp : _components) {
|
||||
comp->deinitialize();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGUIModule::internalInitializeGL() {
|
||||
std::filesystem::path file = FileSys.cacheManager()->cachedFilename("imgui.ini", "");
|
||||
LDEBUG(fmt::format("Using {} as ImGUI cache location", file));
|
||||
|
||||
_iniFileBuffer.resize(file.string().size() + 1);
|
||||
|
||||
#ifdef WIN32
|
||||
strcpy_s(_iniFileBuffer.data(), file.string().size() + 1, file.string().c_str());
|
||||
#else
|
||||
strcpy(_iniFileBuffer.data(), file.c_str());
|
||||
#endif
|
||||
|
||||
int nWindows = global::windowDelegate->nWindows();
|
||||
_contexts.resize(nWindows);
|
||||
|
||||
for (int i = 0; i < nWindows; ++i) {
|
||||
_contexts[i] = ImGui::CreateContext();
|
||||
ImGui::SetCurrentContext(_contexts[i]);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.IniFilename = _iniFileBuffer.data();
|
||||
io.DeltaTime = 1.f / 60.f;
|
||||
io.KeyMap[ImGuiKey_Tab] = static_cast<int>(Key::Tab);
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = static_cast<int>(Key::Left);
|
||||
io.KeyMap[ImGuiKey_RightArrow] = static_cast<int>(Key::Right);
|
||||
io.KeyMap[ImGuiKey_UpArrow] = static_cast<int>(Key::Up);
|
||||
io.KeyMap[ImGuiKey_DownArrow] = static_cast<int>(Key::Down);
|
||||
io.KeyMap[ImGuiKey_Home] = static_cast<int>(Key::Home);
|
||||
io.KeyMap[ImGuiKey_End] = static_cast<int>(Key::End);
|
||||
io.KeyMap[ImGuiKey_Delete] = static_cast<int>(Key::Delete);
|
||||
io.KeyMap[ImGuiKey_Backspace] = static_cast<int>(Key::BackSpace);
|
||||
io.KeyMap[ImGuiKey_Enter] = static_cast<int>(Key::Enter);
|
||||
io.KeyMap[ImGuiKey_Escape] = static_cast<int>(Key::Escape);
|
||||
io.KeyMap[ImGuiKey_A] = static_cast<int>(Key::A);
|
||||
io.KeyMap[ImGuiKey_C] = static_cast<int>(Key::C);
|
||||
io.KeyMap[ImGuiKey_V] = static_cast<int>(Key::V);
|
||||
io.KeyMap[ImGuiKey_X] = static_cast<int>(Key::X);
|
||||
io.KeyMap[ImGuiKey_Y] = static_cast<int>(Key::Y);
|
||||
io.KeyMap[ImGuiKey_Z] = static_cast<int>(Key::Z);
|
||||
|
||||
io.Fonts->AddFontFromFileTTF(absPath(GuiFont).string().c_str(), FontSize);
|
||||
captionFont = io.Fonts->AddFontFromFileTTF(
|
||||
absPath(GuiFont).string().c_str(),
|
||||
FontSize * 1.5f
|
||||
);
|
||||
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
style.WindowPadding = { 4.f, 4.f };
|
||||
style.WindowRounding = 0.f;
|
||||
style.FramePadding = { 3.f, 3.f };
|
||||
style.FrameRounding = 0.f;
|
||||
style.ItemSpacing = { 3.f, 2.f };
|
||||
style.ItemInnerSpacing = { 3.f, 2.f };
|
||||
style.TouchExtraPadding = { 1.f, 1.f };
|
||||
style.IndentSpacing = 15.f;
|
||||
style.ScrollbarSize = 10.f;
|
||||
style.ScrollbarRounding = 0.f;
|
||||
style.GrabMinSize = 10.f;
|
||||
style.GrabRounding = 16.f;
|
||||
|
||||
style.Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
|
||||
style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
|
||||
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.13f, 0.13f, 0.13f, 0.96f);
|
||||
style.Colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||
style.Colors[ImGuiCol_PopupBg] = ImVec4(0.05f, 0.05f, 0.10f, 0.90f);
|
||||
style.Colors[ImGuiCol_Border] = ImVec4(0.65f, 0.65f, 0.65f, 0.59f);
|
||||
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||
style.Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f);
|
||||
style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.91f, 0.94f, 0.99f, 0.40f);
|
||||
style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.90f, 0.90f, 0.90f, 0.45f);
|
||||
style.Colors[ImGuiCol_TitleBg] = ImVec4(0.71f, 0.81f, 1.00f, 0.45f);
|
||||
style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.71f, 0.81f, 1.00f, 0.45f);
|
||||
style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.51f, 0.69f, 1.00f, 0.63f);
|
||||
style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.26f, 0.27f, 0.33f, 0.80f);
|
||||
style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||
style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.75f, 0.80f, 0.43f);
|
||||
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.75f, 0.80f, 0.65f);
|
||||
style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.40f, 0.75f, 0.80f, 0.65f);
|
||||
style.Colors[ImGuiCol_CheckMark] = ImVec4(1.00f, 1.00f, 1.00f, 0.50f);
|
||||
style.Colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
|
||||
style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.50f, 0.80f, 0.76f, 1.00f);
|
||||
style.Colors[ImGuiCol_Button] = ImVec4(0.36f, 0.54f, 0.68f, 0.62f);
|
||||
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.36f, 0.54f, 0.68f, 1.00f);
|
||||
style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.36f, 0.61f, 0.81f, 1.00f);
|
||||
style.Colors[ImGuiCol_Header] = ImVec4(0.69f, 0.69f, 0.69f, 0.45f);
|
||||
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.36f, 0.54f, 0.68f, 0.62f);
|
||||
style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.63f, 0.87f, 0.80f);
|
||||
style.Colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
||||
style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.70f, 0.60f, 0.60f, 1.00f);
|
||||
style.Colors[ImGuiCol_SeparatorActive] = ImVec4(0.90f, 0.70f, 0.70f, 1.00f);
|
||||
style.Colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
||||
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.60f);
|
||||
style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.90f);
|
||||
style.Colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
||||
style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||
style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||
style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
|
||||
style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.44f, 0.63f, 1.00f, 0.35f);
|
||||
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
|
||||
}
|
||||
|
||||
for (gui::GuiComponent* comp : _components) {
|
||||
comp->initialize();
|
||||
}
|
||||
|
||||
_program = ghoul::opengl::ProgramObject::Build(
|
||||
"GUI",
|
||||
absPath("${MODULE_IMGUI}/shaders/gui_vs.glsl"),
|
||||
absPath("${MODULE_IMGUI}/shaders/gui_fs.glsl")
|
||||
);
|
||||
|
||||
ghoul::opengl::updateUniformLocations(*_program, _uniformCache, UniformNames);
|
||||
|
||||
{
|
||||
unsigned char* texData;
|
||||
glm::ivec2 texSize = glm::ivec2(0, 0);
|
||||
for (int i = 0; i < nWindows; ++i) {
|
||||
ImGui::SetCurrentContext(_contexts[i]);
|
||||
|
||||
ImGui::GetIO().Fonts->GetTexDataAsRGBA32(&texData, &texSize.x, &texSize.y);
|
||||
}
|
||||
_fontTexture = std::make_unique<ghoul::opengl::Texture>(
|
||||
texData,
|
||||
glm::uvec3(texSize.x, texSize.y, 1),
|
||||
GL_TEXTURE_2D
|
||||
);
|
||||
_fontTexture->setName("Gui Text");
|
||||
_fontTexture->setDataOwnership(ghoul::opengl::Texture::TakeOwnership::No);
|
||||
_fontTexture->uploadTexture();
|
||||
}
|
||||
for (int i = 0; i < nWindows; ++i) {
|
||||
uintptr_t texture = static_cast<GLuint>(*_fontTexture);
|
||||
ImGui::SetCurrentContext(_contexts[i]);
|
||||
ImGui::GetIO().Fonts->TexID = reinterpret_cast<void*>(texture);
|
||||
}
|
||||
|
||||
glGenBuffers(1, &vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_DYNAMIC_DRAW);
|
||||
|
||||
glGenBuffers(1, &vboElements);
|
||||
|
||||
glGenVertexArrays(1, &vao);
|
||||
glBindVertexArray(vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
|
||||
GLuint positionAttrib = _program->attributeLocation("in_position");
|
||||
GLuint uvAttrib = _program->attributeLocation("in_uv");
|
||||
GLuint colorAttrib = _program->attributeLocation("in_color");
|
||||
|
||||
glEnableVertexAttribArray(positionAttrib);
|
||||
glVertexAttribPointer(
|
||||
positionAttrib,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
sizeof(ImDrawVert),
|
||||
nullptr
|
||||
);
|
||||
|
||||
glEnableVertexAttribArray(uvAttrib);
|
||||
glVertexAttribPointer(
|
||||
uvAttrib,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
sizeof(ImDrawVert),
|
||||
reinterpret_cast<GLvoid*>(offsetof(ImDrawVert, uv))
|
||||
);
|
||||
|
||||
glEnableVertexAttribArray(colorAttrib);
|
||||
glVertexAttribPointer(
|
||||
colorAttrib,
|
||||
4,
|
||||
GL_UNSIGNED_BYTE,
|
||||
GL_TRUE,
|
||||
sizeof(ImDrawVert),
|
||||
reinterpret_cast<GLvoid*>(offsetof(ImDrawVert, col))
|
||||
);
|
||||
glBindVertexArray(0);
|
||||
|
||||
for (gui::GuiComponent* comp : _components) {
|
||||
comp->initializeGL();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGUIModule::internalDeinitializeGL() {
|
||||
_program = nullptr;
|
||||
_fontTexture = nullptr;
|
||||
|
||||
glDeleteVertexArrays(1, &vao);
|
||||
glDeleteBuffers(1, &vbo);
|
||||
glDeleteBuffers(1, &vboElements);
|
||||
|
||||
for (gui::GuiComponent* comp : _components) {
|
||||
comp->deinitializeGL();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGUIModule::renderFrame(float deltaTime, const glm::vec2& windowSize,
|
||||
const glm::vec2& dpiScaling, const glm::vec2& mousePos,
|
||||
uint32_t mouseButtonsPressed)
|
||||
{
|
||||
const int iWindow = global::windowDelegate->currentWindowId();
|
||||
ImGui::SetCurrentContext(_contexts[iWindow]);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2(windowSize.x, windowSize.y);
|
||||
io.DisplayFramebufferScale = ImVec2(dpiScaling.x, dpiScaling.y);
|
||||
io.DeltaTime = deltaTime;
|
||||
|
||||
io.MousePos = ImVec2(mousePos.x, mousePos.y);
|
||||
|
||||
io.MouseDown[0] = mouseButtonsPressed & (1 << 0);
|
||||
io.MouseDown[1] = mouseButtonsPressed & (1 << 1);
|
||||
|
||||
ImGui::NewFrame();
|
||||
|
||||
if (_program->isDirty()) {
|
||||
_program->rebuildFromFile();
|
||||
ghoul::opengl::updateUniformLocations(*_program, _uniformCache, UniformNames);
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
ImGui::SetNextWindowCollapsed(_isCollapsed);
|
||||
|
||||
ImGui::Begin("OpenSpace GUI", nullptr);
|
||||
|
||||
_isCollapsed = ImGui::IsWindowCollapsed();
|
||||
|
||||
for (gui::GuiComponent* comp : _components) {
|
||||
bool enabled = comp->isEnabled();
|
||||
ImGui::Checkbox(comp->guiName().c_str(), &enabled);
|
||||
comp->setEnabled(enabled);
|
||||
}
|
||||
|
||||
// Render and Update property visibility
|
||||
// Fragile! Keep this in sync with properties::Property::Visibility
|
||||
using V = properties::Property::Visibility;
|
||||
int t = static_cast<std::underlying_type_t<V>>(_currentVisibility);
|
||||
|
||||
// Array is sorted by importance
|
||||
std::array<const char*, 4> items = { "User", "Developer", "Hidden", "All" };
|
||||
ImGui::Combo("PropertyVisibility", &t, items.data(), static_cast<int>(items.size()));
|
||||
|
||||
_currentVisibility = static_cast<V>(t);
|
||||
_property.setVisibility(_currentVisibility);
|
||||
|
||||
#ifdef SHOW_IMGUI_HELPERS
|
||||
ImGui::Checkbox("ImGUI Internals", &_showInternals);
|
||||
if (_showInternals) {
|
||||
ImGui::Begin("Style Editor");
|
||||
ImGui::ShowStyleEditor();
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Begin("Test Window");
|
||||
ImGui::ShowDemoWindow();
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Begin("Metrics Window");
|
||||
ImGui::ShowMetricsWindow();
|
||||
ImGui::End();
|
||||
}
|
||||
#endif
|
||||
|
||||
ImGui::End();
|
||||
|
||||
|
||||
for (gui::GuiComponent* comp : _components) {
|
||||
if (comp->isEnabled()) {
|
||||
comp->render();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Render();
|
||||
|
||||
// Drawing
|
||||
ImDrawData* drawData = ImGui::GetDrawData();
|
||||
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays
|
||||
// (screen coordinates != framebuffer coordinates)
|
||||
GLsizei fbWidth = static_cast<GLsizei>(
|
||||
io.DisplaySize.x * io.DisplayFramebufferScale.x
|
||||
);
|
||||
GLsizei fbHeight = static_cast<GLsizei>(
|
||||
io.DisplaySize.y * io.DisplayFramebufferScale.y
|
||||
);
|
||||
if (fbWidth == 0 || fbHeight == 0) {
|
||||
return;
|
||||
}
|
||||
drawData->ScaleClipRects(io.DisplayFramebufferScale);
|
||||
|
||||
// Setup render state:
|
||||
// alpha-blending enabled, no face culling, no depth testing, scissor enabled
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
ghoul::opengl::TextureUnit unit;
|
||||
unit.activate();
|
||||
_fontTexture->bind();
|
||||
|
||||
// Setup orthographic projection matrix
|
||||
const float width = ImGui::GetIO().DisplaySize.x;
|
||||
const float height = ImGui::GetIO().DisplaySize.y;
|
||||
glViewport(0, 0, fbWidth, fbHeight);
|
||||
const glm::mat4 ortho(
|
||||
2.f / width, 0.f, 0.f, 0.f,
|
||||
0.f, 2.f / -height, 0.f, 0.f,
|
||||
0.f, 0.f, -1.f, 0.f,
|
||||
-1.f, 1.f, 0.f, 1.f
|
||||
);
|
||||
_program->activate();
|
||||
|
||||
_program->setUniform(_uniformCache.tex, unit);
|
||||
_program->setUniform(_uniformCache.ortho, ortho);
|
||||
|
||||
glBindVertexArray(vao);
|
||||
|
||||
for (int i = 0; i < drawData->CmdListsCount; ++i) {
|
||||
const ImDrawList* cmdList = drawData->CmdLists[i];
|
||||
const ImDrawIdx* indexBufferOffset = nullptr;
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
cmdList->VtxBuffer.size() * sizeof(ImDrawVert),
|
||||
reinterpret_cast<const GLvoid*>(&cmdList->VtxBuffer.front()),
|
||||
GL_STREAM_DRAW
|
||||
);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboElements);
|
||||
glBufferData(
|
||||
GL_ELEMENT_ARRAY_BUFFER,
|
||||
cmdList->IdxBuffer.size() * sizeof(ImDrawIdx),
|
||||
reinterpret_cast<const GLvoid*>(&cmdList->IdxBuffer.front()),
|
||||
GL_STREAM_DRAW
|
||||
);
|
||||
|
||||
for (const ImDrawCmd* pcmd = cmdList->CmdBuffer.begin();
|
||||
pcmd != cmdList->CmdBuffer.end();
|
||||
pcmd++)
|
||||
{
|
||||
if (pcmd->UserCallback) {
|
||||
pcmd->UserCallback(cmdList, pcmd);
|
||||
}
|
||||
else {
|
||||
glBindTexture(
|
||||
GL_TEXTURE_2D,
|
||||
static_cast<GLuint>(reinterpret_cast<intptr_t>(pcmd->TextureId))
|
||||
);
|
||||
glScissor(
|
||||
static_cast<int>(pcmd->ClipRect.x),
|
||||
static_cast<int>(fbHeight - pcmd->ClipRect.w),
|
||||
static_cast<int>(pcmd->ClipRect.z - pcmd->ClipRect.x),
|
||||
static_cast<int>(pcmd->ClipRect.w - pcmd->ClipRect.y)
|
||||
);
|
||||
glDrawElements(
|
||||
GL_TRIANGLES,
|
||||
static_cast<GLsizei>(pcmd->ElemCount),
|
||||
sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
|
||||
indexBufferOffset
|
||||
);
|
||||
}
|
||||
indexBufferOffset += pcmd->ElemCount;
|
||||
}
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
_program->deactivate();
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
bool ImGUIModule::mouseButtonCallback(MouseButton, MouseAction) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
bool consumeEvent = io.WantCaptureMouse;
|
||||
return consumeEvent;
|
||||
}
|
||||
|
||||
bool ImGUIModule::mouseWheelCallback(double position) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
bool consumeEvent = io.WantCaptureMouse;
|
||||
if (consumeEvent) {
|
||||
io.MouseWheel = static_cast<float>(position);
|
||||
}
|
||||
return consumeEvent;
|
||||
}
|
||||
|
||||
bool ImGUIModule::keyCallback(Key key, KeyModifier modifier, KeyAction action) {
|
||||
const int keyIndex = static_cast<int>(key);
|
||||
if (keyIndex < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool hasShift = hasKeyModifier(modifier, KeyModifier::Shift);
|
||||
const bool hasCtrl = hasKeyModifier(modifier, KeyModifier::Control);
|
||||
const bool hasAlt = hasKeyModifier(modifier, KeyModifier::Alt);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
const bool consumeEvent = io.WantCaptureKeyboard;
|
||||
if (consumeEvent) {
|
||||
if (action == KeyAction::Press) {
|
||||
io.KeysDown[keyIndex] = true;
|
||||
}
|
||||
io.KeyShift = hasShift;
|
||||
io.KeyCtrl = hasCtrl;
|
||||
io.KeyAlt = hasAlt;
|
||||
}
|
||||
|
||||
// Even if the event is not consumed,
|
||||
// set keys and modifiers to false when they are released.
|
||||
if (action == KeyAction::Release) {
|
||||
io.KeysDown[keyIndex] = false;
|
||||
}
|
||||
if (!hasShift) {
|
||||
io.KeyShift = false;
|
||||
}
|
||||
if (!hasCtrl) {
|
||||
io.KeyCtrl = false;
|
||||
}
|
||||
if (!hasAlt) {
|
||||
io.KeyAlt = false;
|
||||
}
|
||||
|
||||
return consumeEvent;
|
||||
}
|
||||
|
||||
bool ImGUIModule::charCallback(unsigned int character, KeyModifier) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
bool consumeEvent = io.WantCaptureKeyboard;
|
||||
if (consumeEvent) {
|
||||
io.AddInputCharacter(static_cast<unsigned short>(character));
|
||||
}
|
||||
return consumeEvent;
|
||||
}
|
||||
|
||||
bool ImGUIModule::touchDetectedCallback(TouchInput input) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
const glm::vec2 windowPos = input.currentWindowCoordinates();
|
||||
const bool consumeEvent = io.WantCaptureMouse;
|
||||
|
||||
if (!consumeEvent) {
|
||||
return false;
|
||||
}
|
||||
if (_validTouchStates.empty()) {
|
||||
io.MousePos = { windowPos.x, windowPos.y };
|
||||
io.MouseClicked[0] = true;
|
||||
}
|
||||
_validTouchStates.push_back(input);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGUIModule::touchUpdatedCallback(TouchInput input) {
|
||||
if (_validTouchStates.empty()) {
|
||||
return false;
|
||||
}
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
auto it = std::find_if(
|
||||
_validTouchStates.cbegin(),
|
||||
_validTouchStates.cend(),
|
||||
[&](const TouchInput& state) {
|
||||
return state.fingerId == input.fingerId &&
|
||||
state.touchDeviceId == input.touchDeviceId;
|
||||
}
|
||||
);
|
||||
|
||||
if (it == _validTouchStates.cbegin()) {
|
||||
glm::vec2 windowPos = input.currentWindowCoordinates();
|
||||
io.MousePos = ImVec2(windowPos.x, windowPos.y);
|
||||
io.MouseClicked[0] = true;
|
||||
return true;
|
||||
}
|
||||
else if (it != _validTouchStates.cend()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ImGUIModule::touchExitCallback(TouchInput input) {
|
||||
if (_validTouchStates.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto found = std::find_if(
|
||||
_validTouchStates.cbegin(),
|
||||
_validTouchStates.cend(),
|
||||
[&](const TouchInput& state) {
|
||||
return state.fingerId == input.fingerId &&
|
||||
state.touchDeviceId == input.touchDeviceId;
|
||||
}
|
||||
);
|
||||
|
||||
if (found == _validTouchStates.cend()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
_validTouchStates.erase(found);
|
||||
if (_validTouchStates.empty()) {
|
||||
glm::vec2 windowPos = input.currentWindowCoordinates();
|
||||
io.MousePos = ImVec2(windowPos.x, windowPos.y);
|
||||
io.MouseClicked[0] = false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -27,7 +27,30 @@
|
||||
|
||||
#include <openspace/util/openspacemodule.h>
|
||||
|
||||
#include <modules/imgui/include/gui.h>
|
||||
#include <modules/imgui/include/guiactioncomponent.h>
|
||||
#include <modules/imgui/include/guifilepathcomponent.h>
|
||||
#include <modules/imgui/include/guigibscomponent.h>
|
||||
#include <modules/imgui/include/guiglobebrowsingcomponent.h>
|
||||
#include <modules/imgui/include/guihelpcomponent.h>
|
||||
#include <modules/imgui/include/guijoystickcomponent.h>
|
||||
#include <modules/imgui/include/guimemorycomponent.h>
|
||||
#include <modules/imgui/include/guimissioncomponent.h>
|
||||
#include <modules/imgui/include/guiparallelcomponent.h>
|
||||
#include <modules/imgui/include/guipropertycomponent.h>
|
||||
#include <modules/imgui/include/guiscenecomponent.h>
|
||||
#include <modules/imgui/include/guispacetimecomponent.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
#include <openspace/util/keys.h>
|
||||
#include <openspace/util/mouse.h>
|
||||
#include <openspace/util/touch.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <ghoul/opengl/uniformcache.h>
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <array>
|
||||
|
||||
struct ImGuiContext;
|
||||
|
||||
namespace openspace {
|
||||
|
||||
@@ -37,13 +60,85 @@ public:
|
||||
|
||||
ImGUIModule();
|
||||
|
||||
gui::GUI gui;
|
||||
void internalInitialize(const ghoul::Dictionary& configuration) override;
|
||||
void internalDeinitialize() override;
|
||||
void internalInitializeGL() override;
|
||||
void internalDeinitializeGL() override;
|
||||
|
||||
private:
|
||||
bool mouseButtonCallback(MouseButton button, MouseAction action);
|
||||
bool mouseWheelCallback(double position);
|
||||
bool keyCallback(Key key, KeyModifier modifier, KeyAction action);
|
||||
bool charCallback(unsigned int character, KeyModifier modifier);
|
||||
|
||||
bool touchDetectedCallback(TouchInput input);
|
||||
bool touchUpdatedCallback(TouchInput input);
|
||||
void touchExitCallback(TouchInput input);
|
||||
|
||||
void renderFrame(float deltaTime, const glm::vec2& windowSize,
|
||||
const glm::vec2& dpiScaling, const glm::vec2& mousePos,
|
||||
uint32_t mouseButtonsPressed);
|
||||
|
||||
properties::BoolProperty _isEnabled;
|
||||
properties::BoolProperty _isCollapsed;
|
||||
|
||||
gui::GuiPropertyComponent _sceneProperty;
|
||||
gui::GuiPropertyComponent _property;
|
||||
gui::GuiSpaceTimeComponent _spaceTime;
|
||||
gui::GuiJoystickComponent _joystick;
|
||||
gui::GuiActionComponent _actions;
|
||||
gui::GuiParallelComponent _parallel;
|
||||
gui::GuiGlobeBrowsingComponent _globeBrowsing;
|
||||
gui::GuiGIBSComponent _gibs;
|
||||
gui::GuiMissionComponent _mission;
|
||||
gui::GuiMemoryComponent _memoryComponent;
|
||||
gui::GuiSceneComponent _sceneView;
|
||||
gui::GuiFilePathComponent _filePath;
|
||||
gui::GuiHelpComponent _help;
|
||||
|
||||
properties::BoolProperty _showHelpText;
|
||||
properties::FloatProperty _helpTextDelay;
|
||||
|
||||
// The ordering of this array determines the order of components in the in-game menu
|
||||
static constexpr int nComponents = 13;
|
||||
std::array<gui::GuiComponent*, nComponents> _components = {
|
||||
&_sceneProperty,
|
||||
&_property,
|
||||
&_spaceTime,
|
||||
&_joystick,
|
||||
&_actions,
|
||||
&_parallel,
|
||||
&_globeBrowsing,
|
||||
&_gibs,
|
||||
&_mission,
|
||||
&_memoryComponent,
|
||||
&_sceneView,
|
||||
&_filePath,
|
||||
&_help
|
||||
};
|
||||
|
||||
GLuint vao = 0;
|
||||
GLuint vbo = 0;
|
||||
GLuint vboElements = 0;
|
||||
std::unique_ptr<ghoul::opengl::ProgramObject> _program;
|
||||
UniformCache(tex, ortho) _uniformCache;
|
||||
std::unique_ptr<ghoul::opengl::Texture> _fontTexture;
|
||||
|
||||
properties::Property::Visibility _currentVisibility =
|
||||
properties::Property::Visibility::Developer;
|
||||
|
||||
std::vector<ImGuiContext*> _contexts;
|
||||
|
||||
std::vector<TouchInput> _validTouchStates;
|
||||
|
||||
std::vector<char> _iniFileBuffer;
|
||||
|
||||
glm::vec2 _mousePosition = glm::vec2(0.f);
|
||||
uint32_t _mouseButtons = 0;
|
||||
};
|
||||
|
||||
void CaptionText(const char* text);
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_IMGUI___IMGUIMODULE___H__
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_IMGUI___GUI___H__
|
||||
#define __OPENSPACE_MODULE_IMGUI___GUI___H__
|
||||
|
||||
#include <modules/imgui/include/guicomponent.h>
|
||||
|
||||
#include <modules/imgui/include/guiactioncomponent.h>
|
||||
#include <modules/imgui/include/guifilepathcomponent.h>
|
||||
#include <modules/imgui/include/guigibscomponent.h>
|
||||
#include <modules/imgui/include/guiglobebrowsingcomponent.h>
|
||||
#include <modules/imgui/include/guihelpcomponent.h>
|
||||
#include <modules/imgui/include/guiiswacomponent.h>
|
||||
#include <modules/imgui/include/guijoystickcomponent.h>
|
||||
#include <modules/imgui/include/guimemorycomponent.h>
|
||||
#include <modules/imgui/include/guimissioncomponent.h>
|
||||
#include <modules/imgui/include/guiparallelcomponent.h>
|
||||
#include <modules/imgui/include/guipropertycomponent.h>
|
||||
#include <modules/imgui/include/guispacetimecomponent.h>
|
||||
#include <openspace/properties/property.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
#include <openspace/util/keys.h>
|
||||
#include <openspace/util/mouse.h>
|
||||
#include <openspace/util/touch.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <ghoul/opengl/uniformcache.h>
|
||||
#include <array>
|
||||
|
||||
//#define SHOW_IMGUI_HELPERS
|
||||
|
||||
struct ImGuiContext;
|
||||
|
||||
namespace ghoul::opengl {
|
||||
class ProgramObject;
|
||||
class Texture;
|
||||
} // namespace ghoul::opengl
|
||||
|
||||
namespace openspace::gui {
|
||||
|
||||
namespace detail {
|
||||
constexpr int nComponents() {
|
||||
const int nRegularComponents = 15;
|
||||
int totalComponents = nRegularComponents;
|
||||
|
||||
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
|
||||
++totalComponents;
|
||||
#endif
|
||||
|
||||
return totalComponents;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
class GUI : public GuiComponent {
|
||||
public:
|
||||
GUI();
|
||||
~GUI();
|
||||
|
||||
void initialize() override;
|
||||
void deinitialize() override;
|
||||
|
||||
void initializeGL() override;
|
||||
void deinitializeGL() override;
|
||||
|
||||
bool mouseButtonCallback(MouseButton button, MouseAction action);
|
||||
bool mouseWheelCallback(double position);
|
||||
bool keyCallback(Key key, KeyModifier modifier, KeyAction action);
|
||||
bool charCallback(unsigned int character, KeyModifier modifier);
|
||||
|
||||
bool touchDetectedCallback(TouchInput input);
|
||||
bool touchUpdatedCallback(TouchInput input);
|
||||
void touchExitCallback(TouchInput input);
|
||||
|
||||
void startFrame(float deltaTime, const glm::vec2& windowSize,
|
||||
const glm::vec2& dpiScaling, const glm::vec2& mousePos,
|
||||
uint32_t mouseButtonsPressed);
|
||||
void endFrame();
|
||||
|
||||
void render() override;
|
||||
|
||||
//protected:
|
||||
GuiHelpComponent _help;
|
||||
GuiFilePathComponent _filePath;
|
||||
GuiGIBSComponent _gibs;
|
||||
GuiGlobeBrowsingComponent _globeBrowsing;
|
||||
|
||||
GuiPropertyComponent _globalProperty;
|
||||
GuiPropertyComponent _sceneProperty;
|
||||
GuiPropertyComponent _screenSpaceProperty;
|
||||
GuiPropertyComponent _moduleProperty;
|
||||
GuiMemoryComponent _memoryComponent;
|
||||
|
||||
GuiSpaceTimeComponent _spaceTime;
|
||||
GuiMissionComponent _mission;
|
||||
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
|
||||
GuiIswaComponent _iswa;
|
||||
#endif // OPENSPACE_MODULE_ISWA_ENABLED
|
||||
GuiActionComponent _actions;
|
||||
GuiJoystickComponent _joystick;
|
||||
GuiParallelComponent _parallel;
|
||||
GuiPropertyComponent _featuredProperties;
|
||||
|
||||
|
||||
properties::BoolProperty _showHelpText;
|
||||
properties::FloatProperty _helpTextDelay;
|
||||
|
||||
private:
|
||||
void renderAndUpdatePropertyVisibility();
|
||||
|
||||
// The ordering of this array determines the order of components in the in-game menu
|
||||
std::array<GuiComponent*, detail::nComponents()> _components = {
|
||||
&_sceneProperty,
|
||||
&_screenSpaceProperty,
|
||||
&_featuredProperties,
|
||||
&_globalProperty,
|
||||
&_moduleProperty,
|
||||
&_memoryComponent,
|
||||
&_spaceTime,
|
||||
&_mission,
|
||||
&_parallel,
|
||||
&_gibs,
|
||||
&_globeBrowsing,
|
||||
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
|
||||
&_iswa,
|
||||
#endif
|
||||
&_actions,
|
||||
&_joystick,
|
||||
&_filePath,
|
||||
&_help
|
||||
};
|
||||
|
||||
GLuint vao = 0;
|
||||
GLuint vbo = 0;
|
||||
GLuint vboElements = 0;
|
||||
std::unique_ptr<ghoul::opengl::ProgramObject> _program;
|
||||
UniformCache(tex, ortho) _uniformCache;
|
||||
std::unique_ptr<ghoul::opengl::Texture> _fontTexture;
|
||||
|
||||
#ifdef SHOW_IMGUI_HELPERS
|
||||
bool _showInternals = false;
|
||||
#endif // SHOW_IMGUI_HELPERS
|
||||
|
||||
properties::Property::Visibility _currentVisibility =
|
||||
properties::Property::Visibility::Developer;
|
||||
|
||||
std::vector<ImGuiContext*> _contexts;
|
||||
|
||||
std::vector<TouchInput> _validTouchStates;
|
||||
};
|
||||
|
||||
void CaptionText(const char* text);
|
||||
|
||||
} // namespace openspace::gui
|
||||
|
||||
#endif // __OPENSPACE_MODULE_IMGUI___GUI___H__
|
||||
@@ -43,16 +43,14 @@ namespace openspace::gui {
|
||||
|
||||
class GuiPropertyComponent : public GuiComponent {
|
||||
public:
|
||||
using SourceFunction = std::function<std::vector<properties::PropertyOwner*>()>;
|
||||
|
||||
BooleanType(UseTreeLayout);
|
||||
|
||||
GuiPropertyComponent(std::string identifier, std::string guiName = "",
|
||||
GuiPropertyComponent(std::string identifier, std::string guiName,
|
||||
UseTreeLayout useTree = UseTreeLayout::No);
|
||||
|
||||
// This is the function that evaluates to the list of Propertyowners that this
|
||||
// component should render
|
||||
void setSource(SourceFunction function);
|
||||
void setPropertyOwners(std::vector<properties::PropertyOwner*> propertyOwners);
|
||||
void setPropertyOwnerFunction(
|
||||
std::function<std::vector<properties::PropertyOwner*>()> func);
|
||||
|
||||
void setVisibility(properties::Property::Visibility visibility);
|
||||
|
||||
@@ -64,7 +62,8 @@ protected:
|
||||
|
||||
properties::Property::Visibility _visibility = properties::Property::Visibility::User;
|
||||
|
||||
SourceFunction _function;
|
||||
std::vector<properties::PropertyOwner*> _propertyOwners;
|
||||
std::function<std::vector<properties::PropertyOwner*>()> _propertyOwnerFunction;
|
||||
|
||||
properties::BoolProperty _useTreeLayout;
|
||||
properties::StringListProperty _treeOrdering;
|
||||
|
||||
@@ -22,34 +22,22 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_IMGUI___GUIISWACOMPONENT___H__
|
||||
#define __OPENSPACE_MODULE_IMGUI___GUIISWACOMPONENT___H__
|
||||
#ifndef __OPENSPACE_MODULE_IMGUI___GUISCENECOMPONENT___H__
|
||||
#define __OPENSPACE_MODULE_IMGUI___GUISCENECOMPONENT___H__
|
||||
|
||||
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
|
||||
#include <modules/imgui/include/guicomponent.h>
|
||||
|
||||
#include <modules/imgui/include/guipropertycomponent.h>
|
||||
|
||||
#include <map>
|
||||
namespace openspace { class SceneGraphNode; }
|
||||
|
||||
namespace openspace::gui {
|
||||
|
||||
class GuiIswaComponent : public GuiPropertyComponent {
|
||||
class GuiSceneComponent : public GuiComponent {
|
||||
public:
|
||||
GuiIswaComponent();
|
||||
GuiSceneComponent();
|
||||
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
bool _gmData = false;
|
||||
bool _gmImage = false;
|
||||
bool _ionData = false;
|
||||
std::vector<int> _cdfOptions;
|
||||
std::map<std::string, int> _cdfOptionsMap;
|
||||
};
|
||||
|
||||
} // namespace openspace::gui
|
||||
|
||||
#endif // OPENSPACE_MODULE_ISWA_ENABLED
|
||||
|
||||
|
||||
#endif // __OPENSPACE_MODULE_IMGUI___GUIISWACOMPONENT___H__
|
||||
#endif // __OPENSPACE_MODULE_IMGUI___GUISCENECOMPONENT___H__
|
||||
@@ -1,796 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/imgui/include/gui.h>
|
||||
|
||||
#include <modules/imgui/imguimodule.h>
|
||||
#include <modules/imgui/include/imgui_include.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/mission/missionmanager.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/filesystem/cachemanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/opengl/textureunit.h>
|
||||
#include <filesystem>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "GUI";
|
||||
constexpr const char* configurationFile = "imgui.ini";
|
||||
constexpr const char* GuiFont = "${FONTS}/arimo/Arimo-Regular.ttf";
|
||||
constexpr const float FontSize = 14.f;
|
||||
|
||||
char* iniFileBuffer = nullptr;
|
||||
|
||||
ImFont* captionFont = nullptr;
|
||||
|
||||
constexpr const std::array<const char*, 2> UniformNames = { "tex", "ortho" };
|
||||
|
||||
void addScreenSpaceRenderableLocal(std::string identifier, std::string texturePath) {
|
||||
if (!std::filesystem::is_regular_file(absPath(texturePath))) {
|
||||
LWARNING(fmt::format("Could not find image '{}'", texturePath));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string script;
|
||||
if (identifier.empty()) {
|
||||
script = fmt::format(
|
||||
"openspace.addScreenSpaceRenderable({{\
|
||||
Type = 'ScreenSpaceImageLocal',\
|
||||
TexturePath = openspace.absPath('{}')\
|
||||
}});",
|
||||
texturePath
|
||||
);
|
||||
}
|
||||
else {
|
||||
script = fmt::format(
|
||||
"openspace.addScreenSpaceRenderable({{\
|
||||
Type = 'ScreenSpaceImageLocal',\
|
||||
TexturePath = openspace.absPath('{}'),\
|
||||
Identifier = '{}',\
|
||||
Name = '{}'\
|
||||
}});",
|
||||
texturePath,
|
||||
identifier,
|
||||
identifier
|
||||
);
|
||||
}
|
||||
|
||||
openspace::global::scriptEngine->queueScript(
|
||||
script,
|
||||
openspace::scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
|
||||
void addScreenSpaceRenderableOnline(std::string identifier, std::string texturePath) {
|
||||
std::string script;
|
||||
if (identifier.empty()) {
|
||||
script = fmt::format(
|
||||
"openspace.addScreenSpaceRenderable({{\
|
||||
Type = 'ScreenSpaceImageOnline',\
|
||||
URL = '{}'\
|
||||
}});",
|
||||
texturePath
|
||||
);
|
||||
}
|
||||
else {
|
||||
script = fmt::format(
|
||||
"openspace.addScreenSpaceRenderable({{\
|
||||
Type = 'ScreenSpaceImageOnline',\
|
||||
URL = '{}',\
|
||||
Identifier = '{}',\
|
||||
Name = '{}'\
|
||||
}});",
|
||||
texturePath,
|
||||
identifier,
|
||||
identifier
|
||||
);
|
||||
}
|
||||
|
||||
openspace::global::scriptEngine->queueScript(
|
||||
script,
|
||||
openspace::scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ShowHelpInfo = {
|
||||
"ShowHelpText",
|
||||
"Show tooltip help",
|
||||
"If this value is enabled these kinds of tooltips are shown for most properties "
|
||||
"explaining what impact they have on the visuals."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo HelpTextDelayInfo = {
|
||||
"HelpTextDelay",
|
||||
"Tooltip Delay (in s)",
|
||||
"This value determines the delay in seconds after which the tooltip is shown."
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace openspace::gui {
|
||||
|
||||
void CaptionText(const char* text) {
|
||||
ImGui::PushFont(captionFont);
|
||||
ImGui::Text("%s", text);
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
GUI::GUI()
|
||||
: GuiComponent("Main")
|
||||
, _globalProperty("Global", "Global Properties")
|
||||
, _sceneProperty(
|
||||
"SceneProperties", "Scene Properties",
|
||||
GuiPropertyComponent::UseTreeLayout::Yes
|
||||
)
|
||||
, _screenSpaceProperty("ScreenSpaceProperties", "ScreenSpace Properties")
|
||||
, _moduleProperty("ModuleProperties", "Module Properties")
|
||||
, _featuredProperties(
|
||||
"FeaturedProperties",
|
||||
"Featured Properties",
|
||||
GuiPropertyComponent::UseTreeLayout::No
|
||||
)
|
||||
, _showHelpText(ShowHelpInfo, true)
|
||||
, _helpTextDelay(HelpTextDelayInfo, 1.0, 0.0, 10.0)
|
||||
{
|
||||
for (GuiComponent* comp : _components) {
|
||||
addPropertySubOwner(comp);
|
||||
}
|
||||
_spaceTime.setEnabled(true);
|
||||
|
||||
{
|
||||
auto showHelpTextFunc = [this]() {
|
||||
for (GuiComponent* comp : _components) {
|
||||
comp->setShowHelpTooltip(_showHelpText);
|
||||
}
|
||||
};
|
||||
showHelpTextFunc();
|
||||
_showHelpText.onChange(std::move(showHelpTextFunc));
|
||||
addProperty(_showHelpText);
|
||||
}
|
||||
|
||||
{
|
||||
auto helpTextDelayFunc = [this](){
|
||||
for (GuiComponent* comp : _components) {
|
||||
comp->setShowHelpTooltipDelay(_helpTextDelay);
|
||||
}
|
||||
};
|
||||
helpTextDelayFunc();
|
||||
_helpTextDelay.onChange(std::move(helpTextDelayFunc));
|
||||
addProperty(_helpTextDelay);
|
||||
}
|
||||
}
|
||||
|
||||
GUI::~GUI() {} // NOLINT
|
||||
|
||||
void GUI::initialize() {}
|
||||
|
||||
void GUI::deinitialize() {
|
||||
for (ImGuiContext* ctx : _contexts) {
|
||||
ImGui::DestroyContext(ctx);
|
||||
}
|
||||
|
||||
for (GuiComponent* comp : _components) {
|
||||
comp->deinitialize();
|
||||
}
|
||||
|
||||
delete iniFileBuffer;
|
||||
}
|
||||
|
||||
void GUI::initializeGL() {
|
||||
std::filesystem::path cachedFile = FileSys.cacheManager()->cachedFilename(
|
||||
configurationFile,
|
||||
""
|
||||
);
|
||||
|
||||
LDEBUG(fmt::format("Using {} as ImGUI cache location", cachedFile));
|
||||
|
||||
iniFileBuffer = new char[cachedFile.string().size() + 1];
|
||||
|
||||
#ifdef WIN32
|
||||
strcpy_s(iniFileBuffer, cachedFile.string().size() + 1, cachedFile.string().c_str());
|
||||
#else
|
||||
strcpy(iniFileBuffer, cachedFile.c_str());
|
||||
#endif
|
||||
|
||||
int nWindows = global::windowDelegate->nWindows();
|
||||
_contexts.resize(nWindows);
|
||||
|
||||
for (int i = 0; i < nWindows; ++i) {
|
||||
_contexts[i] = ImGui::CreateContext();
|
||||
ImGui::SetCurrentContext(_contexts[i]);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.IniFilename = iniFileBuffer;
|
||||
io.DeltaTime = 1.f / 60.f;
|
||||
io.KeyMap[ImGuiKey_Tab] = static_cast<int>(Key::Tab);
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = static_cast<int>(Key::Left);
|
||||
io.KeyMap[ImGuiKey_RightArrow] = static_cast<int>(Key::Right);
|
||||
io.KeyMap[ImGuiKey_UpArrow] = static_cast<int>(Key::Up);
|
||||
io.KeyMap[ImGuiKey_DownArrow] = static_cast<int>(Key::Down);
|
||||
io.KeyMap[ImGuiKey_Home] = static_cast<int>(Key::Home);
|
||||
io.KeyMap[ImGuiKey_End] = static_cast<int>(Key::End);
|
||||
io.KeyMap[ImGuiKey_Delete] = static_cast<int>(Key::Delete);
|
||||
io.KeyMap[ImGuiKey_Backspace] = static_cast<int>(Key::BackSpace);
|
||||
io.KeyMap[ImGuiKey_Enter] = static_cast<int>(Key::Enter);
|
||||
io.KeyMap[ImGuiKey_Escape] = static_cast<int>(Key::Escape);
|
||||
io.KeyMap[ImGuiKey_A] = static_cast<int>(Key::A);
|
||||
io.KeyMap[ImGuiKey_C] = static_cast<int>(Key::C);
|
||||
io.KeyMap[ImGuiKey_V] = static_cast<int>(Key::V);
|
||||
io.KeyMap[ImGuiKey_X] = static_cast<int>(Key::X);
|
||||
io.KeyMap[ImGuiKey_Y] = static_cast<int>(Key::Y);
|
||||
io.KeyMap[ImGuiKey_Z] = static_cast<int>(Key::Z);
|
||||
|
||||
io.Fonts->AddFontFromFileTTF(absPath(GuiFont).string().c_str(), FontSize);
|
||||
captionFont = io.Fonts->AddFontFromFileTTF(
|
||||
absPath(GuiFont).string().c_str(),
|
||||
FontSize * 1.5f
|
||||
);
|
||||
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
style.WindowPadding = { 4.f, 4.f };
|
||||
style.WindowRounding = 0.f;
|
||||
style.FramePadding = { 3.f, 3.f };
|
||||
style.FrameRounding = 0.f;
|
||||
style.ItemSpacing = { 3.f, 2.f };
|
||||
style.ItemInnerSpacing = { 3.f, 2.f };
|
||||
style.TouchExtraPadding = { 1.f, 1.f };
|
||||
style.IndentSpacing = 15.f;
|
||||
style.ScrollbarSize = 10.f;
|
||||
style.ScrollbarRounding = 0.f;
|
||||
style.GrabMinSize = 10.f;
|
||||
style.GrabRounding = 16.f;
|
||||
|
||||
style.Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
|
||||
style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
|
||||
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.13f, 0.13f, 0.13f, 0.96f);
|
||||
style.Colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||
style.Colors[ImGuiCol_PopupBg] = ImVec4(0.05f, 0.05f, 0.10f, 0.90f);
|
||||
style.Colors[ImGuiCol_Border] = ImVec4(0.65f, 0.65f, 0.65f, 0.59f);
|
||||
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||
style.Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f);
|
||||
style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.91f, 0.94f, 0.99f, 0.40f);
|
||||
style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.90f, 0.90f, 0.90f, 0.45f);
|
||||
style.Colors[ImGuiCol_TitleBg] = ImVec4(0.71f, 0.81f, 1.00f, 0.45f);
|
||||
style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.71f, 0.81f, 1.00f, 0.45f);
|
||||
style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.51f, 0.69f, 1.00f, 0.63f);
|
||||
style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.26f, 0.27f, 0.33f, 0.80f);
|
||||
style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||
style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.75f, 0.80f, 0.43f);
|
||||
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.75f, 0.80f, 0.65f);
|
||||
style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.40f, 0.75f, 0.80f, 0.65f);
|
||||
style.Colors[ImGuiCol_CheckMark] = ImVec4(1.00f, 1.00f, 1.00f, 0.50f);
|
||||
style.Colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
|
||||
style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.50f, 0.80f, 0.76f, 1.00f);
|
||||
style.Colors[ImGuiCol_Button] = ImVec4(0.36f, 0.54f, 0.68f, 0.62f);
|
||||
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.36f, 0.54f, 0.68f, 1.00f);
|
||||
style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.36f, 0.61f, 0.81f, 1.00f);
|
||||
style.Colors[ImGuiCol_Header] = ImVec4(0.69f, 0.69f, 0.69f, 0.45f);
|
||||
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.36f, 0.54f, 0.68f, 0.62f);
|
||||
style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.63f, 0.87f, 0.80f);
|
||||
style.Colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
||||
style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.70f, 0.60f, 0.60f, 1.00f);
|
||||
style.Colors[ImGuiCol_SeparatorActive] = ImVec4(0.90f, 0.70f, 0.70f, 1.00f);
|
||||
style.Colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
||||
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.60f);
|
||||
style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.90f);
|
||||
style.Colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
||||
style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||
style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||
style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
|
||||
style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.44f, 0.63f, 1.00f, 0.35f);
|
||||
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
|
||||
}
|
||||
|
||||
for (GuiComponent* comp : _components) {
|
||||
comp->initialize();
|
||||
}
|
||||
|
||||
_program = ghoul::opengl::ProgramObject::Build(
|
||||
"GUI",
|
||||
absPath("${MODULE_IMGUI}/shaders/gui_vs.glsl"),
|
||||
absPath("${MODULE_IMGUI}/shaders/gui_fs.glsl")
|
||||
);
|
||||
|
||||
ghoul::opengl::updateUniformLocations(*_program, _uniformCache, UniformNames);
|
||||
|
||||
{
|
||||
unsigned char* texData;
|
||||
glm::ivec2 texSize = glm::ivec2(0);
|
||||
for (int i = 0; i < nWindows; ++i) {
|
||||
//_contexts[i] = ImGui::CreateContext();
|
||||
ImGui::SetCurrentContext(_contexts[i]);
|
||||
|
||||
ImGui::GetIO().Fonts->GetTexDataAsRGBA32(&texData, &texSize.x, &texSize.y);
|
||||
}
|
||||
_fontTexture = std::make_unique<ghoul::opengl::Texture>(
|
||||
texData,
|
||||
glm::uvec3(texSize.x, texSize.y, 1),
|
||||
GL_TEXTURE_2D
|
||||
);
|
||||
_fontTexture->setName("Gui Text");
|
||||
_fontTexture->setDataOwnership(ghoul::opengl::Texture::TakeOwnership::No);
|
||||
_fontTexture->uploadTexture();
|
||||
}
|
||||
for (int i = 0; i < nWindows; ++i) {
|
||||
uintptr_t texture = static_cast<GLuint>(*_fontTexture);
|
||||
ImGui::SetCurrentContext(_contexts[i]);
|
||||
ImGui::GetIO().Fonts->TexID = reinterpret_cast<void*>(texture);
|
||||
}
|
||||
|
||||
glGenBuffers(1, &vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_DYNAMIC_DRAW);
|
||||
|
||||
glGenBuffers(1, &vboElements);
|
||||
|
||||
glGenVertexArrays(1, &vao);
|
||||
glBindVertexArray(vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
|
||||
GLuint positionAttrib = _program->attributeLocation("in_position");
|
||||
GLuint uvAttrib = _program->attributeLocation("in_uv");
|
||||
GLuint colorAttrib = _program->attributeLocation("in_color");
|
||||
|
||||
glEnableVertexAttribArray(positionAttrib);
|
||||
glVertexAttribPointer(
|
||||
positionAttrib,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
sizeof(ImDrawVert),
|
||||
nullptr
|
||||
);
|
||||
glEnableVertexAttribArray(uvAttrib);
|
||||
glVertexAttribPointer(
|
||||
uvAttrib,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
sizeof(ImDrawVert),
|
||||
reinterpret_cast<GLvoid*>(offsetof(ImDrawVert, uv)) // NOLINT
|
||||
);
|
||||
glEnableVertexAttribArray(colorAttrib);
|
||||
glVertexAttribPointer(
|
||||
colorAttrib,
|
||||
4,
|
||||
GL_UNSIGNED_BYTE,
|
||||
GL_TRUE,
|
||||
sizeof(ImDrawVert),
|
||||
reinterpret_cast<GLvoid*>(offsetof(ImDrawVert, col)) // NOLINT
|
||||
);
|
||||
glBindVertexArray(0);
|
||||
|
||||
for (GuiComponent* comp : _components) {
|
||||
comp->initializeGL();
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::deinitializeGL() {
|
||||
_program = nullptr;
|
||||
_fontTexture = nullptr;
|
||||
|
||||
glDeleteVertexArrays(1, &vao);
|
||||
glDeleteBuffers(1, &vbo);
|
||||
glDeleteBuffers(1, &vboElements);
|
||||
|
||||
for (GuiComponent* comp : _components) {
|
||||
comp->deinitializeGL();
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::startFrame(float deltaTime, const glm::vec2& windowSize,
|
||||
const glm::vec2& dpiScaling, const glm::vec2& mousePos,
|
||||
uint32_t mouseButtonsPressed)
|
||||
{
|
||||
const int iWindow = global::windowDelegate->currentWindowId();
|
||||
ImGui::SetCurrentContext(_contexts[iWindow]);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2(windowSize.x, windowSize.y);
|
||||
io.DisplayFramebufferScale = ImVec2(dpiScaling.x, dpiScaling.y);
|
||||
io.DeltaTime = deltaTime;
|
||||
|
||||
io.MousePos = ImVec2(mousePos.x, mousePos.y);
|
||||
|
||||
io.MouseDown[0] = mouseButtonsPressed & (1 << 0);
|
||||
io.MouseDown[1] = mouseButtonsPressed & (1 << 1);
|
||||
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
void GUI::endFrame() {
|
||||
if (_program->isDirty()) {
|
||||
_program->rebuildFromFile();
|
||||
ghoul::opengl::updateUniformLocations(*_program, _uniformCache, UniformNames);
|
||||
}
|
||||
|
||||
if (_isEnabled) {
|
||||
render();
|
||||
|
||||
for (GuiComponent* comp : _components) {
|
||||
if (comp->isEnabled()) {
|
||||
comp->render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Render();
|
||||
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Drawing
|
||||
ImDrawData* drawData = ImGui::GetDrawData();
|
||||
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays
|
||||
// (screen coordinates != framebuffer coordinates)
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
GLsizei fb_width = static_cast<GLsizei>(
|
||||
io.DisplaySize.x * io.DisplayFramebufferScale.x
|
||||
);
|
||||
GLsizei fb_height = static_cast<GLsizei>(
|
||||
io.DisplaySize.y * io.DisplayFramebufferScale.y
|
||||
);
|
||||
if (fb_width == 0 || fb_height == 0) {
|
||||
return;
|
||||
}
|
||||
drawData->ScaleClipRects(io.DisplayFramebufferScale);
|
||||
|
||||
// Setup render state:
|
||||
// alpha-blending enabled, no face culling, no depth testing, scissor enabled
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
ghoul::opengl::TextureUnit unit;
|
||||
unit.activate();
|
||||
_fontTexture->bind();
|
||||
|
||||
// Setup orthographic projection matrix
|
||||
const float width = ImGui::GetIO().DisplaySize.x;
|
||||
const float height = ImGui::GetIO().DisplaySize.y;
|
||||
glViewport(0, 0, fb_width, fb_height);
|
||||
const glm::mat4 ortho(
|
||||
2.f / width, 0.0f, 0.0f, 0.f,
|
||||
0.0f, 2.0f / -height, 0.0f, 0.f,
|
||||
0.0f, 0.0f, -1.0f, 0.0f,
|
||||
-1.0f, 1.0f, 0.0f, 1.0f
|
||||
);
|
||||
_program->activate();
|
||||
|
||||
_program->setUniform(_uniformCache.tex, unit);
|
||||
_program->setUniform(_uniformCache.ortho, ortho);
|
||||
|
||||
glBindVertexArray(vao);
|
||||
|
||||
for (int i = 0; i < drawData->CmdListsCount; ++i) {
|
||||
const ImDrawList* cmdList = drawData->CmdLists[i];
|
||||
const ImDrawIdx* indexBufferOffset = nullptr;
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
cmdList->VtxBuffer.size() * sizeof(ImDrawVert),
|
||||
reinterpret_cast<const GLvoid*>(&cmdList->VtxBuffer.front()),
|
||||
GL_STREAM_DRAW
|
||||
);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboElements);
|
||||
glBufferData(
|
||||
GL_ELEMENT_ARRAY_BUFFER,
|
||||
cmdList->IdxBuffer.size() * sizeof(ImDrawIdx),
|
||||
reinterpret_cast<const GLvoid*>(&cmdList->IdxBuffer.front()),
|
||||
GL_STREAM_DRAW
|
||||
);
|
||||
|
||||
for (const ImDrawCmd* pcmd = cmdList->CmdBuffer.begin();
|
||||
pcmd != cmdList->CmdBuffer.end();
|
||||
pcmd++)
|
||||
{
|
||||
if (pcmd->UserCallback) {
|
||||
pcmd->UserCallback(cmdList, pcmd);
|
||||
}
|
||||
else {
|
||||
glBindTexture(
|
||||
GL_TEXTURE_2D,
|
||||
static_cast<GLuint>(reinterpret_cast<intptr_t>(pcmd->TextureId))
|
||||
);
|
||||
glScissor(
|
||||
static_cast<int>(pcmd->ClipRect.x),
|
||||
static_cast<int>(fb_height - pcmd->ClipRect.w),
|
||||
static_cast<int>(pcmd->ClipRect.z - pcmd->ClipRect.x),
|
||||
static_cast<int>(pcmd->ClipRect.w - pcmd->ClipRect.y)
|
||||
);
|
||||
glDrawElements(
|
||||
GL_TRIANGLES,
|
||||
static_cast<GLsizei>(pcmd->ElemCount),
|
||||
sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
|
||||
indexBufferOffset
|
||||
);
|
||||
}
|
||||
indexBufferOffset += pcmd->ElemCount;
|
||||
}
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
_program->deactivate();
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
bool GUI::mouseButtonCallback(MouseButton, MouseAction) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
bool consumeEvent = io.WantCaptureMouse;
|
||||
return consumeEvent;
|
||||
}
|
||||
|
||||
bool GUI::mouseWheelCallback(double position) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
bool consumeEvent = io.WantCaptureMouse;
|
||||
if (consumeEvent) {
|
||||
io.MouseWheel = static_cast<float>(position);
|
||||
}
|
||||
|
||||
return consumeEvent;
|
||||
}
|
||||
|
||||
bool GUI::keyCallback(Key key, KeyModifier modifier, KeyAction action) {
|
||||
const int keyIndex = static_cast<int>(key);
|
||||
if (keyIndex < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool hasShift = hasKeyModifier(modifier, KeyModifier::Shift);
|
||||
const bool hasCtrl = hasKeyModifier(modifier, KeyModifier::Control);
|
||||
const bool hasAlt = hasKeyModifier(modifier, KeyModifier::Alt);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
const bool consumeEvent = io.WantCaptureKeyboard;
|
||||
if (consumeEvent) {
|
||||
if (action == KeyAction::Press) {
|
||||
io.KeysDown[keyIndex] = true;
|
||||
}
|
||||
io.KeyShift = hasShift;
|
||||
io.KeyCtrl = hasCtrl;
|
||||
io.KeyAlt = hasAlt;
|
||||
}
|
||||
|
||||
// Even if the event is not consumed,
|
||||
// set keys and modifiers to false when they are released.
|
||||
if (action == KeyAction::Release) {
|
||||
io.KeysDown[keyIndex] = false;
|
||||
}
|
||||
if (!hasShift) {
|
||||
io.KeyShift = false;
|
||||
}
|
||||
if (!hasCtrl) {
|
||||
io.KeyCtrl = false;
|
||||
}
|
||||
if (!hasAlt) {
|
||||
io.KeyAlt = false;
|
||||
}
|
||||
|
||||
return consumeEvent;
|
||||
}
|
||||
|
||||
bool GUI::charCallback(unsigned int character, KeyModifier) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
bool consumeEvent = io.WantCaptureKeyboard;
|
||||
|
||||
if (consumeEvent) {
|
||||
io.AddInputCharacter(static_cast<unsigned short>(character));
|
||||
}
|
||||
|
||||
return consumeEvent;
|
||||
}
|
||||
|
||||
bool GUI::touchDetectedCallback(TouchInput input) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
const glm::vec2 windowPos = input.currentWindowCoordinates();
|
||||
const bool consumeEvent = io.WantCaptureMouse;
|
||||
|
||||
if (!consumeEvent) {
|
||||
return false;
|
||||
}
|
||||
if (_validTouchStates.empty()) {
|
||||
io.MousePos = {windowPos.x, windowPos.y};
|
||||
io.MouseClicked[0] = true;
|
||||
}
|
||||
_validTouchStates.push_back(input);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GUI::touchUpdatedCallback(TouchInput input) {
|
||||
if (_validTouchStates.empty()) {
|
||||
return false;
|
||||
}
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
auto it = std::find_if(
|
||||
_validTouchStates.cbegin(),
|
||||
_validTouchStates.cend(),
|
||||
[&](const TouchInput& state){
|
||||
return state.fingerId == input.fingerId &&
|
||||
state.touchDeviceId == input.touchDeviceId;
|
||||
}
|
||||
);
|
||||
|
||||
if (it == _validTouchStates.cbegin()) {
|
||||
glm::vec2 windowPos = input.currentWindowCoordinates();
|
||||
io.MousePos = {windowPos.x, windowPos.y};
|
||||
io.MouseClicked[0] = true;
|
||||
return true;
|
||||
}
|
||||
else if (it != _validTouchStates.cend()){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GUI::touchExitCallback(TouchInput input) {
|
||||
if (_validTouchStates.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto found = std::find_if(
|
||||
_validTouchStates.cbegin(),
|
||||
_validTouchStates.cend(),
|
||||
[&](const TouchInput& state){
|
||||
return state.fingerId == input.fingerId &&
|
||||
state.touchDeviceId == input.touchDeviceId;
|
||||
}
|
||||
);
|
||||
|
||||
if (found == _validTouchStates.cend()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
_validTouchStates.erase(found);
|
||||
if (_validTouchStates.empty()) {
|
||||
glm::vec2 windowPos = input.currentWindowCoordinates();
|
||||
io.MousePos = {windowPos.x, windowPos.y};
|
||||
io.MouseClicked[0] = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GUI::render() {
|
||||
ImGui::SetNextWindowCollapsed(_isCollapsed);
|
||||
|
||||
ImGui::Begin("OpenSpace GUI", nullptr);
|
||||
|
||||
_isCollapsed = ImGui::IsWindowCollapsed();
|
||||
|
||||
for (GuiComponent* comp : _components) {
|
||||
bool enabled = comp->isEnabled();
|
||||
ImGui::Checkbox(comp->guiName().c_str(), &enabled);
|
||||
comp->setEnabled(enabled);
|
||||
}
|
||||
|
||||
renderAndUpdatePropertyVisibility();
|
||||
|
||||
static const int addImageBufferSize = 256;
|
||||
static char identifierBuffer[addImageBufferSize];
|
||||
static char addImageLocalBuffer[addImageBufferSize];
|
||||
static char addImageOnlineBuffer[addImageBufferSize];
|
||||
|
||||
ImGui::InputText(
|
||||
"Identifier for Local/Online Images",
|
||||
identifierBuffer,
|
||||
addImageBufferSize
|
||||
);
|
||||
|
||||
bool addImageLocal = ImGui::InputText(
|
||||
"Add Local Image",
|
||||
addImageLocalBuffer,
|
||||
addImageBufferSize,
|
||||
ImGuiInputTextFlags_EnterReturnsTrue
|
||||
);
|
||||
if (addImageLocal) {
|
||||
addScreenSpaceRenderableLocal(
|
||||
std::string(identifierBuffer),
|
||||
std::string(addImageLocalBuffer)
|
||||
);
|
||||
}
|
||||
|
||||
bool addImageOnline = ImGui::InputText(
|
||||
"Add Online Image",
|
||||
addImageOnlineBuffer,
|
||||
addImageBufferSize,
|
||||
ImGuiInputTextFlags_EnterReturnsTrue
|
||||
);
|
||||
|
||||
if (addImageOnline) {
|
||||
addScreenSpaceRenderableOnline(
|
||||
std::string(identifierBuffer),
|
||||
std::string(addImageOnlineBuffer)
|
||||
);
|
||||
}
|
||||
|
||||
bool addDashboard = ImGui::Button("Add New Dashboard");
|
||||
if (addDashboard) {
|
||||
global::scriptEngine->queueScript(
|
||||
"openspace.addScreenSpaceRenderable({ Type = 'ScreenSpaceDashboard' });",
|
||||
openspace::scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
|
||||
bool addDashboardCopy = ImGui::Button("Add Copy of Main Dashboard");
|
||||
if (addDashboardCopy) {
|
||||
global::scriptEngine->queueScript(
|
||||
"openspace.addScreenSpaceRenderable({ "
|
||||
"Type = 'ScreenSpaceDashboard', UseMainDashboard = true "
|
||||
"});",
|
||||
openspace::scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef SHOW_IMGUI_HELPERS
|
||||
ImGui::Checkbox("ImGUI Internals", &_showInternals);
|
||||
if (_showInternals) {
|
||||
ImGui::Begin("Style Editor");
|
||||
ImGui::ShowStyleEditor();
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Begin("Test Window");
|
||||
ImGui::ShowDemoWindow();
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Begin("Metrics Window");
|
||||
ImGui::ShowMetricsWindow();
|
||||
ImGui::End();
|
||||
}
|
||||
#endif
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void GUI::renderAndUpdatePropertyVisibility() {
|
||||
// Fragile! Keep this in sync with properties::Property::Visibility
|
||||
using V = properties::Property::Visibility;
|
||||
int t = static_cast<std::underlying_type_t<V>>(_currentVisibility);
|
||||
|
||||
// Array is sorted by importance
|
||||
std::array<const char*, 4> items = { "User", "Developer", "Hidden", "All"};
|
||||
ImGui::Combo("PropertyVisibility", &t, items.data(), static_cast<int>(items.size()));
|
||||
|
||||
_currentVisibility = static_cast<V>(t);
|
||||
_globalProperty.setVisibility(_currentVisibility);
|
||||
_moduleProperty.setVisibility(_currentVisibility);
|
||||
_sceneProperty.setVisibility(_currentVisibility);
|
||||
_screenSpaceProperty.setVisibility(_currentVisibility);
|
||||
_featuredProperties.setVisibility(_currentVisibility);
|
||||
}
|
||||
|
||||
} // namespace openspace::gui
|
||||
@@ -24,19 +24,18 @@
|
||||
|
||||
#include <modules/imgui/include/guiactioncomponent.h>
|
||||
|
||||
#include <modules/imgui/include/gui.h>
|
||||
#include <modules/imgui/imguimodule.h>
|
||||
#include <modules/imgui/include/imgui_include.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/interaction/actionmanager.h>
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <openspace/util/keys.h>
|
||||
|
||||
#include <modules/imgui/include/imgui_include.h>
|
||||
#include <set>
|
||||
|
||||
namespace openspace::gui {
|
||||
|
||||
GuiActionComponent::GuiActionComponent()
|
||||
: GuiComponent("Shortcuts", "Shortcuts")
|
||||
: GuiComponent("Actions", "Actions")
|
||||
{}
|
||||
|
||||
void GuiActionComponent::render() {
|
||||
@@ -92,6 +91,7 @@ void GuiActionComponent::render() {
|
||||
ImGui::Text("(%s)", "local");
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
} // namespace openspace::gui
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
namespace openspace::gui {
|
||||
|
||||
GuiFilePathComponent::GuiFilePathComponent() : GuiComponent("FilePath", "File Path") {}
|
||||
GuiFilePathComponent::GuiFilePathComponent() : GuiComponent("FilePaths", "File Paths") {}
|
||||
|
||||
void GuiFilePathComponent::render() {
|
||||
ImGui::SetNextWindowCollapsed(_isCollapsed);
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
|
||||
|
||||
#include <modules/imgui/include/guiiswacomponent.h>
|
||||
|
||||
#include <modules/imgui/include/imgui_include.h>
|
||||
#include <modules/iswa/util/iswamanager.h>
|
||||
#include <openspace/json.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
|
||||
namespace {
|
||||
using json = nlohmann::json;
|
||||
const ImVec2 WindowSize = ImVec2(350, 500);
|
||||
} // namespace
|
||||
|
||||
namespace openspace::gui {
|
||||
|
||||
GuiIswaComponent::GuiIswaComponent() : GuiPropertyComponent("iSWA") {}
|
||||
|
||||
void GuiIswaComponent::render() {
|
||||
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
|
||||
const bool oldGmDataValue = _gmData;
|
||||
const bool oldGmImageValue = _gmImage;
|
||||
const bool oldIonDataValue = _ionData;
|
||||
|
||||
ImGui::SetNextWindowCollapsed(_isCollapsed);
|
||||
|
||||
bool e = _isEnabled;
|
||||
ImGui::Begin("ISWA", &e, WindowSize, 0.5f);
|
||||
_isEnabled = e;
|
||||
_isCollapsed = ImGui::IsWindowCollapsed();
|
||||
|
||||
ImGui::Text("Global Magnetosphere");
|
||||
ImGui::Checkbox("Gm From Data", &_gmData);
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Gm From Images", &_gmImage);
|
||||
|
||||
ImGui::Text("Ionosphere");
|
||||
ImGui::Checkbox("Ion From Data", &_ionData);
|
||||
|
||||
ImGui::Spacing();
|
||||
constexpr const int AddCygnetBufferSize = 256;
|
||||
static char addCygnetBuffer[AddCygnetBufferSize];
|
||||
ImGui::InputText("addCynget", addCygnetBuffer, AddCygnetBufferSize);
|
||||
|
||||
if (ImGui::SmallButton("Add Cygnet")) {
|
||||
global::scriptEngine->queueScript(
|
||||
"openspace.iswa.addCygnet(" + std::string(addCygnetBuffer) + ");",
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
|
||||
if (_gmData != oldGmDataValue) {
|
||||
if (_gmData) {
|
||||
constexpr const char* script = R"(
|
||||
openspace.iswa.addCygnet(-4, 'Data', 'GMData');
|
||||
openspace.iswa.addCygnet(-5, 'Data', 'GMData');
|
||||
openspace.iswa.addCygnet(-6, 'Data', 'GMData');
|
||||
)";
|
||||
global::scriptEngine->queueScript(
|
||||
script,
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
else {
|
||||
global::scriptEngine->queueScript(
|
||||
"openspace.iswa.removeGroup('GMData');",
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (_gmImage != oldGmImageValue) {
|
||||
if (_gmImage) {
|
||||
constexpr const char* script = R"(
|
||||
openspace.iswa.addCygnet(-4, 'Texture', 'GMImage');
|
||||
openspace.iswa.addCygnet(-5, 'Texture', 'GMImage');
|
||||
openspace.iswa.addCygnet(-6, 'Texture', 'GMImage');
|
||||
)";
|
||||
global::scriptEngine->queueScript(
|
||||
script,
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
else {
|
||||
global::scriptEngine->queueScript(
|
||||
"openspace.iswa.removeGroup('GMImage');",
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (_ionData != oldIonDataValue) {
|
||||
if (_ionData) {
|
||||
global::scriptEngine->queueScript(
|
||||
"openspace.iswa.addCygnet(-10, 'Data', 'Ionosphere');",
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
else {
|
||||
global::scriptEngine->queueScript(
|
||||
"openspace.iswa.removeGroup('Ionosphere');",
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Cdf Files")) {
|
||||
const std::map<std::string, std::vector<CdfInfo>>& cdfInfo =
|
||||
IswaManager::ref().cdfInformation();
|
||||
|
||||
using K = std::string;
|
||||
using V = std::vector<CdfInfo>;
|
||||
for (const std::pair<const K, V>& group : cdfInfo) {
|
||||
const std::string& groupName = group.first;
|
||||
if (_cdfOptionsMap.find(groupName) == _cdfOptionsMap.end()) {
|
||||
_cdfOptionsMap[groupName] = -1;
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader(groupName.c_str())) {
|
||||
int cdfOptionValue = _cdfOptionsMap[groupName];
|
||||
const std::vector<CdfInfo>& cdfs = group.second;
|
||||
|
||||
for (size_t i = 0; i < cdfs.size(); ++i) {
|
||||
ImGui::RadioButton(
|
||||
cdfs[i].name.c_str(),
|
||||
&_cdfOptionsMap[groupName],
|
||||
static_cast<int>(i)
|
||||
);
|
||||
}
|
||||
|
||||
const int cdfOption = _cdfOptionsMap[groupName];
|
||||
if (cdfOptionValue != cdfOption) {
|
||||
const std::string& date = cdfs[cdfOption].date;
|
||||
global::scriptEngine->queueScript(
|
||||
"openspace.iswa.addKameleonPlanes('" +
|
||||
cdfs[cdfOption].group +
|
||||
"'," +
|
||||
std::to_string(cdfOption) +
|
||||
");",
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
global::scriptEngine->queueScript(
|
||||
"openspace.time.setTime('" + date + "');",
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
global::scriptEngine->queueScript(
|
||||
"openspace.time.setDeltaTime(0);",
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GuiPropertyComponent::render();
|
||||
|
||||
if (ImGui::CollapsingHeader("iSWA screen space cygntes")) {
|
||||
const std::map<int, std::shared_ptr<CygnetInfo>>& map =
|
||||
IswaManager::ref().cygnetInformation();
|
||||
|
||||
for (const std::pair<const int, std::shared_ptr<CygnetInfo>>& cygnetInfo : map) {
|
||||
int id = cygnetInfo.first;
|
||||
CygnetInfo& info = *cygnetInfo.second;
|
||||
|
||||
bool selected = info.selected;
|
||||
ImGui::Checkbox(info.name.c_str(), &info.selected);
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::CollapsingHeader(("Description" + std::to_string(id)).c_str())) {
|
||||
ImGui::TextWrapped("%s", info.description.c_str());
|
||||
ImGui::Spacing();
|
||||
}
|
||||
|
||||
if (selected != info.selected) {
|
||||
const std::string idStr = std::to_string(id);
|
||||
if (info.selected) {
|
||||
global::scriptEngine->queueScript(
|
||||
"openspace.iswa.addScreenSpaceCygnet({CygnetId=" + idStr + "});",
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
else {
|
||||
global::scriptEngine->queueScript(
|
||||
"openspace.iswa.removeScreenSpaceCygnet(" + idStr + ");",
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace openspace::gui
|
||||
|
||||
#endif // OPENSPACE_MODULE_ISWA_ENABLED
|
||||
@@ -60,8 +60,9 @@ void GuiJoystickComponent::render() {
|
||||
ImGui::Text("%s", "Axes");
|
||||
for (int j = 0; j < state.nAxes; ++j) {
|
||||
float f = state.axes[j];
|
||||
std::string id = std::to_string(j) + "##" + state.name + "Axis";
|
||||
ImGui::SliderFloat(
|
||||
std::to_string(j).c_str(),
|
||||
id.c_str(),
|
||||
&f,
|
||||
-1.f,
|
||||
1.f
|
||||
@@ -69,8 +70,9 @@ void GuiJoystickComponent::render() {
|
||||
}
|
||||
ImGui::Text("%s", "Buttons");
|
||||
for (int j = 0; j < state.nButtons; ++j) {
|
||||
std::string id = std::to_string(j) + "##" + state.name + "Button";
|
||||
ImGui::RadioButton(
|
||||
std::to_string(j).c_str(),
|
||||
id.c_str(),
|
||||
state.buttons[j] == JoystickAction::Press ||
|
||||
state.buttons[j] == JoystickAction::Repeat
|
||||
);
|
||||
@@ -84,19 +86,21 @@ void GuiJoystickComponent::render() {
|
||||
|
||||
ImGui::Text("%s", "Summed contributions");
|
||||
ImGui::Text("%s", "Axes");
|
||||
for (int i = 0; i < JoystickInputState::MaxAxes; ++i) {
|
||||
for (int i = 0; i < global::joystickInputStates->numAxes(); ++i) {
|
||||
float f = global::joystickInputStates->axis("", i);
|
||||
std::string id = std::to_string(i) + "##" + "TotalAxis";
|
||||
ImGui::SliderFloat(
|
||||
std::to_string(i).c_str(),
|
||||
id.c_str(),
|
||||
&f,
|
||||
-1.f,
|
||||
1.f
|
||||
);
|
||||
}
|
||||
ImGui::Text("%s", "Buttons");
|
||||
for (int i = 0; i < JoystickInputState::MaxButtons; ++i) {
|
||||
for (int i = 0; i < global::joystickInputStates->numButtons(); ++i) {
|
||||
std::string id = std::to_string(i) + "##" + "TotalButton";
|
||||
ImGui::RadioButton(
|
||||
std::to_string(i).c_str(),
|
||||
id.c_str(),
|
||||
global::joystickInputStates->button("", i, JoystickAction::Press) ||
|
||||
global::joystickInputStates->button("", i, JoystickAction::Repeat)
|
||||
);
|
||||
|
||||
@@ -24,13 +24,11 @@
|
||||
|
||||
#include <modules/imgui/include/guimissioncomponent.h>
|
||||
|
||||
#include <modules/imgui/include/gui.h>
|
||||
#include <modules/imgui/imguimodule.h>
|
||||
#include <modules/imgui/include/imgui_include.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/mission/mission.h>
|
||||
#include <openspace/mission/missionmanager.h>
|
||||
#include <openspace/util/timerange.h>
|
||||
#include <openspace/util/time.h>
|
||||
#include <openspace/util/timemanager.h>
|
||||
|
||||
namespace {
|
||||
@@ -61,7 +59,7 @@ namespace {
|
||||
openspace::Time startTime = openspace::Time(range.start);
|
||||
openspace::Time endTime = openspace::Time(range.end);
|
||||
|
||||
openspace::gui::CaptionText("Mission Progress");
|
||||
openspace::CaptionText("Mission Progress");
|
||||
|
||||
ImGui::Text("%s", std::string(startTime.UTC()).c_str());
|
||||
ImGui::SameLine();
|
||||
@@ -79,7 +77,7 @@ namespace {
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s", std::string(endTime.UTC()).c_str());
|
||||
|
||||
openspace::gui::CaptionText("Phases");
|
||||
openspace::CaptionText("Phases");
|
||||
|
||||
for (const openspace::Mission& m : mission.phases()) {
|
||||
renderMission(m);
|
||||
@@ -98,9 +96,7 @@ GuiMissionComponent::GuiMissionComponent()
|
||||
{}
|
||||
|
||||
void GuiMissionComponent::render() {
|
||||
if (!global::missionManager->hasCurrentMission()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ImGui::SetNextWindowCollapsed(_isCollapsed);
|
||||
bool v = _isEnabled;
|
||||
@@ -111,8 +107,13 @@ void GuiMissionComponent::render() {
|
||||
|
||||
_isCollapsed = ImGui::IsWindowCollapsed();
|
||||
|
||||
const Mission& currentMission = global::missionManager->currentMission();
|
||||
renderMission(currentMission);
|
||||
if (global::missionManager->hasCurrentMission()) {
|
||||
const Mission& currentMission = global::missionManager->currentMission();
|
||||
renderMission(currentMission);
|
||||
}
|
||||
else {
|
||||
ImGui::Text("%s", "No mission loaded");
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
@@ -159,7 +159,6 @@ void GuiParallelComponent::renderHost() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GuiParallelComponent::render() {
|
||||
ImGui::SetNextWindowCollapsed(_isCollapsed);
|
||||
bool v = _isEnabled;
|
||||
|
||||
@@ -194,8 +194,16 @@ GuiPropertyComponent::GuiPropertyComponent(std::string identifier, std::string g
|
||||
addProperty(_ignoreHiddenHint);
|
||||
}
|
||||
|
||||
void GuiPropertyComponent::setSource(SourceFunction function) {
|
||||
_function = std::move(function);
|
||||
void GuiPropertyComponent::setPropertyOwners(
|
||||
std::vector<properties::PropertyOwner*> propertyOwners)
|
||||
{
|
||||
_propertyOwners = std::move(propertyOwners);
|
||||
}
|
||||
|
||||
void GuiPropertyComponent::setPropertyOwnerFunction(
|
||||
std::function<std::vector<properties::PropertyOwner*>()> func)
|
||||
{
|
||||
_propertyOwnerFunction = std::move(func);
|
||||
}
|
||||
|
||||
void GuiPropertyComponent::setVisibility(properties::Property::Visibility visibility) {
|
||||
@@ -282,182 +290,167 @@ void GuiPropertyComponent::render() {
|
||||
_isCollapsed = ImGui::IsWindowCollapsed();
|
||||
using namespace properties;
|
||||
|
||||
if (_function) {
|
||||
std::vector<properties::PropertyOwner*> owners = _function();
|
||||
std::vector<properties::PropertyOwner*> owners =
|
||||
_propertyOwnerFunction ? _propertyOwnerFunction() : _propertyOwners;
|
||||
|
||||
std::sort(
|
||||
std::sort(
|
||||
owners.begin(),
|
||||
owners.end(),
|
||||
[](properties::PropertyOwner* lhs, properties::PropertyOwner* rhs) {
|
||||
return lhs->guiName() < rhs->guiName();
|
||||
}
|
||||
);
|
||||
|
||||
if (_useTreeLayout) {
|
||||
for (properties::PropertyOwner* owner : owners) {
|
||||
ghoul_assert(
|
||||
dynamic_cast<SceneGraphNode*>(owner),
|
||||
"When using the tree layout, all owners must be SceneGraphNodes"
|
||||
);
|
||||
(void)owner; // using [[maybe_unused]] in the for loop gives an error
|
||||
}
|
||||
|
||||
// Sort:
|
||||
// if guigrouping, sort by name and shortest first, but respect the user specified
|
||||
// ordering then all w/o guigroup
|
||||
const std::vector<std::string>& ordering = _treeOrdering;
|
||||
std::stable_sort(
|
||||
owners.begin(),
|
||||
owners.end(),
|
||||
[](properties::PropertyOwner* lhs, properties::PropertyOwner* rhs) {
|
||||
return lhs->guiName() < rhs->guiName();
|
||||
}
|
||||
);
|
||||
[&ordering](PropertyOwner* lhs, PropertyOwner* rhs) {
|
||||
std::string lhsGroup = dynamic_cast<SceneGraphNode*>(lhs)->guiPath();
|
||||
std::string rhsGroup = dynamic_cast<SceneGraphNode*>(rhs)->guiPath();
|
||||
|
||||
if (_useTreeLayout) {
|
||||
for (properties::PropertyOwner* owner : owners) {
|
||||
ghoul_assert(
|
||||
dynamic_cast<SceneGraphNode*>(owner),
|
||||
"When using the tree layout, all owners must be SceneGraphNodes"
|
||||
);
|
||||
(void)owner; // using [[maybe_unused]] in the for loop gives an error
|
||||
}
|
||||
if (lhsGroup.empty()) {
|
||||
return false;
|
||||
}
|
||||
if (rhsGroup.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sort:
|
||||
// if guigrouping, sort by name and shortest first, but respect the user
|
||||
// specified ordering
|
||||
// then all w/o guigroup
|
||||
const std::vector<std::string>& ordering = _treeOrdering;
|
||||
std::stable_sort(
|
||||
owners.begin(),
|
||||
owners.end(),
|
||||
[&ordering](PropertyOwner* lhs, PropertyOwner* rhs) {
|
||||
std::string lhsGroup = dynamic_cast<SceneGraphNode*>(lhs)->guiPath();
|
||||
std::string rhsGroup = dynamic_cast<SceneGraphNode*>(rhs)->guiPath();
|
||||
if (ordering.empty()) {
|
||||
return lhsGroup < rhsGroup;
|
||||
}
|
||||
|
||||
if (lhsGroup.empty()) {
|
||||
return false;
|
||||
}
|
||||
if (rhsGroup.empty()) {
|
||||
return true;
|
||||
}
|
||||
std::vector<std::string> lhsToken = ghoul::tokenizeString(lhsGroup, '/');
|
||||
// The first token is always empty
|
||||
auto lhsIt = std::find(ordering.begin(), ordering.end(), lhsToken[1]);
|
||||
|
||||
if (ordering.empty()) {
|
||||
return lhsGroup < rhsGroup;
|
||||
}
|
||||
std::vector<std::string> rhsToken = ghoul::tokenizeString(rhsGroup, '/');
|
||||
// The first token is always empty
|
||||
auto rhsIt = std::find(ordering.begin(), ordering.end(), rhsToken[1]);
|
||||
|
||||
std::vector<std::string> lhsToken = ghoul::tokenizeString(
|
||||
lhsGroup,
|
||||
'/'
|
||||
);
|
||||
// The first token is always empty
|
||||
auto lhsIt = std::find(ordering.begin(), ordering.end(), lhsToken[1]);
|
||||
|
||||
std::vector<std::string> rhsToken = ghoul::tokenizeString(
|
||||
rhsGroup,
|
||||
'/'
|
||||
);
|
||||
// The first token is always empty
|
||||
auto rhsIt = std::find(ordering.begin(), ordering.end(), rhsToken[1]);
|
||||
|
||||
if (lhsIt != ordering.end() && rhsIt != ordering.end()) {
|
||||
if (lhsToken[1] != rhsToken[1]) {
|
||||
// If both top-level groups are in the ordering list, the
|
||||
// order of the iterators gives us the order of the groups
|
||||
return lhsIt < rhsIt;
|
||||
}
|
||||
else {
|
||||
return lhsGroup < rhsGroup;
|
||||
}
|
||||
}
|
||||
else if (lhsIt != ordering.end() && rhsIt == ordering.end()) {
|
||||
// If only one of them is in the list, we have a sorting
|
||||
return true;
|
||||
}
|
||||
else if (lhsIt == ordering.end() && rhsIt != ordering.end()) {
|
||||
return false;
|
||||
if (lhsIt != ordering.end() && rhsIt != ordering.end()) {
|
||||
if (lhsToken[1] != rhsToken[1]) {
|
||||
// If both top-level groups are in the ordering list, the
|
||||
// order of the iterators gives us the order of the groups
|
||||
return lhsIt < rhsIt;
|
||||
}
|
||||
else {
|
||||
return lhsGroup < rhsGroup;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// If the owners list is empty, we wnat to do the normal thing (-> nothing)
|
||||
// Otherwise, check if the first owner has a GUI group
|
||||
// This makes the assumption that the tree layout is only used if the owners are
|
||||
// SceenGraphNodes (checked above)
|
||||
const bool noGuiGroups = owners.empty() ||
|
||||
(dynamic_cast<SceneGraphNode*>(*owners.begin()) &&
|
||||
dynamic_cast<SceneGraphNode*>(*owners.begin())->guiPath().empty());
|
||||
|
||||
auto renderProp = [&](properties::PropertyOwner* pOwner) {
|
||||
const int count = nVisibleProperties(
|
||||
pOwner->propertiesRecursive(),
|
||||
_visibility
|
||||
);
|
||||
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto header = [&]() -> bool {
|
||||
if (owners.size() > 1) {
|
||||
// Create a header in case we have multiple owners
|
||||
return ImGui::CollapsingHeader(pOwner->guiName().c_str());
|
||||
}
|
||||
else if (!pOwner->identifier().empty()) {
|
||||
// If the owner has a name, print it first
|
||||
ImGui::Text("%s", pOwner->guiName().c_str());
|
||||
ImGui::Spacing();
|
||||
else if (lhsIt != ordering.end() && rhsIt == ordering.end()) {
|
||||
// If only one of them is in the list, we have a sorting
|
||||
return true;
|
||||
}
|
||||
else if (lhsIt == ordering.end() && rhsIt != ordering.end()) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// Otherwise, do nothing
|
||||
return true;
|
||||
return lhsGroup < rhsGroup;
|
||||
}
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (header()) {
|
||||
renderPropertyOwner(pOwner);
|
||||
// If the owners list is empty, we wnat to do the normal thing (-> nothing)
|
||||
// Otherwise, check if the first owner has a GUI group
|
||||
// This makes the assumption that the tree layout is only used if the owners are
|
||||
// SceenGraphNodes (checked above)
|
||||
const bool noGuiGroups = owners.empty() ||
|
||||
(dynamic_cast<SceneGraphNode*>(*owners.begin()) &&
|
||||
dynamic_cast<SceneGraphNode*>(*owners.begin())->guiPath().empty());
|
||||
|
||||
auto renderProp = [&](properties::PropertyOwner* pOwner) {
|
||||
const int count = nVisibleProperties(pOwner->propertiesRecursive(), _visibility);
|
||||
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto header = [&]() -> bool {
|
||||
if (owners.size() > 1) {
|
||||
// Create a header in case we have multiple owners
|
||||
return ImGui::CollapsingHeader(pOwner->guiName().c_str());
|
||||
}
|
||||
else if (!pOwner->identifier().empty()) {
|
||||
// If the owner has a name, print it first
|
||||
ImGui::Text("%s", pOwner->guiName().c_str());
|
||||
ImGui::Spacing();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// Otherwise, do nothing
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
if (!_useTreeLayout || noGuiGroups) {
|
||||
if (!_ignoreHiddenHint) {
|
||||
// Remove all of the nodes that we want hidden first
|
||||
owners.erase(
|
||||
std::remove_if(
|
||||
owners.begin(),
|
||||
owners.end(),
|
||||
[](properties::PropertyOwner* p) {
|
||||
SceneGraphNode* s = dynamic_cast<SceneGraphNode*>(p);
|
||||
return s && s->hasGuiHintHidden();
|
||||
}
|
||||
),
|
||||
owners.end()
|
||||
);
|
||||
}
|
||||
std::for_each(owners.begin(), owners.end(), renderProp);
|
||||
if (header()) {
|
||||
renderPropertyOwner(pOwner);
|
||||
}
|
||||
else { // _useTreeLayout && gui groups exist
|
||||
TreeNode root("");
|
||||
};
|
||||
|
||||
for (properties::PropertyOwner* pOwner : owners) {
|
||||
// We checked above that pOwner is a SceneGraphNode
|
||||
SceneGraphNode* nOwner = static_cast<SceneGraphNode*>(pOwner);
|
||||
if (!_ignoreHiddenHint && nOwner->hasGuiHintHidden()) {
|
||||
continue;
|
||||
}
|
||||
const std::string guiPath = nOwner->guiPath();
|
||||
if (guiPath.empty()) {
|
||||
// We know that we are done now since we stable_sort:ed them above
|
||||
break;
|
||||
}
|
||||
std::vector<std::string> paths = ghoul::tokenizeString(
|
||||
guiPath.substr(1),
|
||||
'/'
|
||||
);
|
||||
if (!_useTreeLayout || noGuiGroups) {
|
||||
if (!_ignoreHiddenHint) {
|
||||
// Remove all of the nodes that we want hidden first
|
||||
owners.erase(
|
||||
std::remove_if(
|
||||
owners.begin(),
|
||||
owners.end(),
|
||||
[](properties::PropertyOwner* p) {
|
||||
SceneGraphNode* s = dynamic_cast<SceneGraphNode*>(p);
|
||||
return s && s->hasGuiHintHidden();
|
||||
}
|
||||
),
|
||||
owners.end()
|
||||
);
|
||||
}
|
||||
std::for_each(owners.begin(), owners.end(), renderProp);
|
||||
}
|
||||
else { // _useTreeLayout && gui groups exist
|
||||
TreeNode root("");
|
||||
|
||||
addPathToTree(root, paths, nOwner);
|
||||
for (properties::PropertyOwner* pOwner : owners) {
|
||||
// We checked above that pOwner is a SceneGraphNode
|
||||
SceneGraphNode* nOwner = static_cast<SceneGraphNode*>(pOwner);
|
||||
if (!_ignoreHiddenHint && nOwner->hasGuiHintHidden()) {
|
||||
continue;
|
||||
}
|
||||
const std::string gui = nOwner->guiPath();
|
||||
if (gui.empty()) {
|
||||
// We know that we are done now since we stable_sort:ed them above
|
||||
break;
|
||||
}
|
||||
std::vector<std::string> paths = ghoul::tokenizeString(gui.substr(1), '/');
|
||||
addPathToTree(root, paths, nOwner);
|
||||
}
|
||||
|
||||
simplifyTree(root);
|
||||
|
||||
renderTree(root, renderProp);
|
||||
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 20.f);
|
||||
|
||||
for (properties::PropertyOwner* pOwner : owners) {
|
||||
// We checked above that pOwner is a SceneGraphNode
|
||||
SceneGraphNode* nOwner = static_cast<SceneGraphNode*>(pOwner);
|
||||
|
||||
if (!nOwner->guiPath().empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
simplifyTree(root);
|
||||
|
||||
renderTree(root, renderProp);
|
||||
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 20.f);
|
||||
|
||||
for (properties::PropertyOwner* pOwner : owners) {
|
||||
// We checked above that pOwner is a SceneGraphNode
|
||||
SceneGraphNode* nOwner = static_cast<SceneGraphNode*>(pOwner);
|
||||
|
||||
if (!nOwner->guiPath().empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
renderProp(pOwner);
|
||||
}
|
||||
renderProp(pOwner);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
113
modules/imgui/src/guiscenecomponent.cpp
Normal file
113
modules/imgui/src/guiscenecomponent.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/imgui/include/guiscenecomponent.h>
|
||||
|
||||
#include <modules/imgui/imguimodule.h>
|
||||
#include <modules/imgui/include/imgui_include.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/util/timemanager.h>
|
||||
#include <ghoul/misc/misc.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
const ImVec2 Size = ImVec2(350, 500);
|
||||
|
||||
void renderSceneGraphNode(const openspace::SceneGraphNode& node,
|
||||
const openspace::Time& time)
|
||||
{
|
||||
using namespace openspace;
|
||||
|
||||
if (ImGui::TreeNode(node.identifier().c_str())) {
|
||||
std::vector<SceneGraphNode*> children = node.children();
|
||||
for (SceneGraphNode* c : children) {
|
||||
renderSceneGraphNode(*c, time);
|
||||
}
|
||||
|
||||
bool timeRangeActive = node.isTimeFrameActive(time);
|
||||
ImGui::Checkbox("Time Range Active", &timeRangeActive);
|
||||
|
||||
const Renderable* renderable = node.renderable();
|
||||
if (renderable) {
|
||||
CaptionText("Renderable");
|
||||
bool enabled = renderable->isEnabled();
|
||||
ImGui::Checkbox("Enabled", &enabled);
|
||||
|
||||
bool isVisible = renderable->isVisible();
|
||||
ImGui::Checkbox("Is Visible", &isVisible);
|
||||
|
||||
bool shouldUpdateIfDisabled = renderable->shouldUpdateIfDisabled();
|
||||
ImGui::Checkbox("Should update if disabled", &shouldUpdateIfDisabled);
|
||||
|
||||
bool isReady = renderable->isReady();
|
||||
ImGui::Checkbox("Is Ready", &isReady);
|
||||
|
||||
Renderable::RenderBin bin = renderable->renderBin();
|
||||
std::string binStr = [](Renderable::RenderBin bin) {
|
||||
switch (bin) {
|
||||
case Renderable::RenderBin::Background:
|
||||
return "Background";
|
||||
case Renderable::RenderBin::Opaque:
|
||||
return "Opaque";
|
||||
case Renderable::RenderBin::PreDeferredTransparent:
|
||||
return "PreDeferredTransparent";
|
||||
case Renderable::RenderBin::PostDeferredTransparent:
|
||||
return "PostDeferredTransparent";
|
||||
case Renderable::RenderBin::Overlay:
|
||||
return "Overlay";
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}(bin);
|
||||
ImGui::Text("RenderBin: %s", binStr.c_str());
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace openspace::gui {
|
||||
|
||||
GuiSceneComponent::GuiSceneComponent() : GuiComponent("SceneView", "Scene View") {}
|
||||
|
||||
void GuiSceneComponent::render() {
|
||||
ImGui::SetNextWindowCollapsed(_isCollapsed);
|
||||
|
||||
bool v = _isEnabled;
|
||||
ImGui::Begin("File Path", &v);
|
||||
_isEnabled = v;
|
||||
_isCollapsed = ImGui::IsWindowCollapsed();
|
||||
|
||||
SceneGraphNode* root = global::renderEngine->scene()->root();
|
||||
const Time& now = global::timeManager->time();
|
||||
renderSceneGraphNode(*root, now);
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
} // namespace openspace::gui
|
||||
@@ -24,22 +24,17 @@
|
||||
|
||||
#include <modules/imgui/include/guispacetimecomponent.h>
|
||||
|
||||
#include <modules/imgui/include/gui.h>
|
||||
#include <modules/imgui/imguimodule.h>
|
||||
#include <modules/imgui/include/imgui_include.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/navigation/navigationhandler.h>
|
||||
#include <openspace/navigation/orbitalnavigator.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/util/time.h>
|
||||
#include <openspace/util/timeconversion.h>
|
||||
#include <openspace/util/timemanager.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
|
||||
#include <numeric>
|
||||
|
||||
namespace {
|
||||
const ImVec2 Size = ImVec2(350, 500);
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ void renderTooltip(Property* prop, double delay) {
|
||||
|
||||
void executeSetPropertyScript(const std::string& id, const std::string& value) {
|
||||
global::scriptEngine->queueScript(
|
||||
"openspace.setPropertyValueSingle('" + id + "', " + value + ");",
|
||||
fmt::format("openspace.setPropertyValueSingle('{}', {});", id, value),
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
@@ -115,46 +115,47 @@ void renderOptionProperty(Property* prop, const std::string& ownerName,
|
||||
int value = *p;
|
||||
const std::vector<OptionProperty::Option>& options = p->options();
|
||||
switch (p->displayType()) {
|
||||
case OptionProperty::DisplayType::Radio: {
|
||||
ImGui::Text("%s", name.c_str());
|
||||
ImGui::Separator();
|
||||
for (const OptionProperty::Option& o : options) {
|
||||
ImGui::RadioButton(o.description.c_str(), &value, o.value);
|
||||
case OptionProperty::DisplayType::Radio: {
|
||||
ImGui::Text("%s", name.c_str());
|
||||
ImGui::Separator();
|
||||
for (const OptionProperty::Option& o : options) {
|
||||
ImGui::RadioButton(o.description.c_str(), &value, o.value);
|
||||
if (showTooltip) {
|
||||
renderTooltip(prop, tooltipDelay);
|
||||
}
|
||||
}
|
||||
ImGui::Separator();
|
||||
break;
|
||||
}
|
||||
case OptionProperty::DisplayType::Dropdown: {
|
||||
// The order of the options does not have to correspond with the value of the
|
||||
// option
|
||||
std::string nodeNames;
|
||||
for (const OptionProperty::Option& o : options) {
|
||||
nodeNames += o.description + '\0';
|
||||
}
|
||||
nodeNames += '\0';
|
||||
|
||||
int idx = static_cast<int>(std::distance(
|
||||
options.begin(),
|
||||
std::find_if(
|
||||
options.begin(),
|
||||
options.end(),
|
||||
[value](const OptionProperty::Option& o) { return o.value == value; }
|
||||
)
|
||||
));
|
||||
|
||||
const bool hasChanged = ImGui::Combo(name.c_str(), &idx, nodeNames.c_str());
|
||||
if (showTooltip) {
|
||||
renderTooltip(prop, tooltipDelay);
|
||||
}
|
||||
}
|
||||
ImGui::Separator();
|
||||
break;
|
||||
}
|
||||
case OptionProperty::DisplayType::Dropdown: {
|
||||
// The order of the options does not have to correspond with the value of the
|
||||
// option
|
||||
std::string nodeNames;
|
||||
for (const OptionProperty::Option& o : options) {
|
||||
nodeNames += o.description + '\0';
|
||||
}
|
||||
nodeNames += '\0';
|
||||
|
||||
int idx = static_cast<int>(std::distance(
|
||||
options.begin(),
|
||||
std::find_if(
|
||||
options.begin(),
|
||||
options.end(),
|
||||
[value](const OptionProperty::Option& o) { return o.value == value; }
|
||||
)));
|
||||
if (hasChanged) {
|
||||
value = options[idx].value;
|
||||
}
|
||||
|
||||
const bool hasChanged = ImGui::Combo(name.c_str(), &idx, nodeNames.c_str());
|
||||
if (showTooltip) {
|
||||
renderTooltip(prop, tooltipDelay);
|
||||
break;
|
||||
}
|
||||
|
||||
if (hasChanged) {
|
||||
value = options[idx].value;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (value != p->value() && !isReadOnly) {
|
||||
executeSetPropertyScript(p->fullyQualifiedIdentifier(), std::to_string(value));
|
||||
@@ -170,10 +171,10 @@ void renderSelectionProperty(Property* prop, const std::string& ownerName,
|
||||
const std::string& name = p->guiName();
|
||||
ImGui::PushID((ownerName + '.' + name).c_str());
|
||||
|
||||
bool selectionChanged = false;
|
||||
std::set<std::string> newSelected;
|
||||
|
||||
if (ImGui::TreeNode(name.c_str())) {
|
||||
bool selectionChanged = false;
|
||||
std::set<std::string> newSelected;
|
||||
|
||||
std::set<std::string> selected = p->value();
|
||||
const std::vector<std::string>& options = p->options();
|
||||
|
||||
@@ -224,12 +225,7 @@ void renderStringProperty(Property* prop, const std::string& ownerName,
|
||||
#else
|
||||
strcpy(buffer, value.c_str());
|
||||
#endif
|
||||
bool hasNewValue = ImGui::InputText(
|
||||
name.c_str(),
|
||||
buffer,
|
||||
bufferSize,
|
||||
ImGuiInputTextFlags_EnterReturnsTrue
|
||||
);
|
||||
bool hasNewValue = ImGui::InputText(name.c_str(), buffer, bufferSize);
|
||||
if (showTooltip) {
|
||||
renderTooltip(prop, tooltipDelay);
|
||||
}
|
||||
@@ -262,13 +258,8 @@ void renderListProperty(const std::string& name, const std::string& fullIdentifi
|
||||
#else
|
||||
strcpy(buffer, value.c_str());
|
||||
#endif
|
||||
bool hasNewValue = ImGui::InputText(
|
||||
name.c_str(),
|
||||
buffer,
|
||||
bufferSize,
|
||||
ImGuiInputTextFlags_EnterReturnsTrue
|
||||
);
|
||||
|
||||
|
||||
bool hasNewValue = ImGui::InputText(name.c_str(), buffer, bufferSize);
|
||||
if (hasNewValue) {
|
||||
std::vector<std::string> tokens = ghoul::tokenizeString(std::string(buffer), ',');
|
||||
std::string script = "{";
|
||||
@@ -415,21 +406,13 @@ void renderIVec2Property(Property* prop, const std::string& ownerName,
|
||||
IVec2Property::ValueType value = *p;
|
||||
int min = glm::compMin(p->minValue());
|
||||
int max = glm::compMax(p->maxValue());
|
||||
bool changed = ImGui::SliderInt2(
|
||||
name.c_str(),
|
||||
&value.x,
|
||||
min,
|
||||
max
|
||||
);
|
||||
bool changed = ImGui::SliderInt2(name.c_str(), &value.x, min, max);
|
||||
if (showTooltip) {
|
||||
renderTooltip(prop, tooltipDelay);
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
executeSetPropertyScript(
|
||||
p->fullyQualifiedIdentifier(),
|
||||
ghoul::to_string(value)
|
||||
);
|
||||
executeSetPropertyScript(p->fullyQualifiedIdentifier(), ghoul::to_string(value));
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
@@ -447,21 +430,13 @@ void renderIVec3Property(Property* prop, const std::string& ownerName,
|
||||
int min = glm::compMin(p->minValue());
|
||||
int max = glm::compMax(p->maxValue());
|
||||
|
||||
bool changed = ImGui::SliderInt3(
|
||||
name.c_str(),
|
||||
&value.x,
|
||||
min,
|
||||
max
|
||||
);
|
||||
bool changed = ImGui::SliderInt3(name.c_str(), &value.x, min, max);
|
||||
if (showTooltip) {
|
||||
renderTooltip(prop, tooltipDelay);
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
executeSetPropertyScript(
|
||||
p->fullyQualifiedIdentifier(),
|
||||
ghoul::to_string(value)
|
||||
);
|
||||
executeSetPropertyScript(p->fullyQualifiedIdentifier(), ghoul::to_string(value));
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
@@ -478,21 +453,13 @@ void renderIVec4Property(Property* prop, const std::string& ownerName,
|
||||
int min = glm::compMin(p->minValue());
|
||||
int max = glm::compMax(p->maxValue());
|
||||
|
||||
bool changed = ImGui::SliderInt4(
|
||||
name.c_str(),
|
||||
&value.x,
|
||||
min,
|
||||
max
|
||||
);
|
||||
bool changed = ImGui::SliderInt4(name.c_str(), &value.x, min, max);
|
||||
if (showTooltip) {
|
||||
renderTooltip(prop, tooltipDelay);
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
executeSetPropertyScript(
|
||||
p->fullyQualifiedIdentifier(),
|
||||
ghoul::to_string(value)
|
||||
);
|
||||
executeSetPropertyScript(p->fullyQualifiedIdentifier(), ghoul::to_string(value));
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
@@ -552,10 +519,7 @@ void renderVec2Property(Property* prop, const std::string& ownerName,
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
executeSetPropertyScript(
|
||||
p->fullyQualifiedIdentifier(),
|
||||
ghoul::to_string(value)
|
||||
);
|
||||
executeSetPropertyScript(p->fullyQualifiedIdentifier(), ghoul::to_string(value));
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
@@ -575,10 +539,7 @@ void renderVec3Property(Property* prop, const std::string& ownerName,
|
||||
|
||||
bool changed = false;
|
||||
if (prop->viewOption(Property::ViewOptions::Color)) {
|
||||
changed = ImGui::ColorEdit3(
|
||||
name.c_str(),
|
||||
glm::value_ptr(value)
|
||||
);
|
||||
changed = ImGui::ColorEdit3(name.c_str(), glm::value_ptr(value));
|
||||
}
|
||||
else {
|
||||
changed = ImGui::SliderFloat3(
|
||||
@@ -595,10 +556,7 @@ void renderVec3Property(Property* prop, const std::string& ownerName,
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
executeSetPropertyScript(
|
||||
p->fullyQualifiedIdentifier(),
|
||||
ghoul::to_string(value)
|
||||
);
|
||||
executeSetPropertyScript(p->fullyQualifiedIdentifier(), ghoul::to_string(value));
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
@@ -618,10 +576,7 @@ void renderVec4Property(Property* prop, const std::string& ownerName,
|
||||
|
||||
bool changed = false;
|
||||
if (prop->viewOption(Property::ViewOptions::Color)) {
|
||||
changed = ImGui::ColorEdit4(
|
||||
name.c_str(),
|
||||
glm::value_ptr(value)
|
||||
);
|
||||
changed = ImGui::ColorEdit4(name.c_str(), glm::value_ptr(value));
|
||||
}
|
||||
else {
|
||||
changed = ImGui::SliderFloat4(
|
||||
@@ -638,10 +593,7 @@ void renderVec4Property(Property* prop, const std::string& ownerName,
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
executeSetPropertyScript(
|
||||
p->fullyQualifiedIdentifier(),
|
||||
ghoul::to_string(value)
|
||||
);
|
||||
executeSetPropertyScript(p->fullyQualifiedIdentifier(), ghoul::to_string(value));
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
@@ -671,10 +623,7 @@ void renderDVec2Property(Property* prop, const std::string& ownerName,
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
executeSetPropertyScript(
|
||||
p->fullyQualifiedIdentifier(),
|
||||
ghoul::to_string(value)
|
||||
);
|
||||
executeSetPropertyScript(p->fullyQualifiedIdentifier(), ghoul::to_string(value));
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
@@ -705,10 +654,7 @@ void renderDVec3Property(Property* prop, const std::string& ownerName,
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
executeSetPropertyScript(
|
||||
p->fullyQualifiedIdentifier(),
|
||||
ghoul::to_string(value)
|
||||
);
|
||||
executeSetPropertyScript(p->fullyQualifiedIdentifier(), ghoul::to_string(value));
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
@@ -739,10 +685,7 @@ void renderDVec4Property(Property* prop, const std::string& ownerName,
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
executeSetPropertyScript(
|
||||
p->fullyQualifiedIdentifier(),
|
||||
ghoul::to_string(value)
|
||||
);
|
||||
executeSetPropertyScript(p->fullyQualifiedIdentifier(), ghoul::to_string(value));
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
@@ -794,10 +737,7 @@ void renderDMat2Property(Property* prop, const std::string& ownerName,
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
executeSetPropertyScript(
|
||||
p->fullyQualifiedIdentifier(),
|
||||
ghoul::to_string(value)
|
||||
);
|
||||
executeSetPropertyScript(p->fullyQualifiedIdentifier(), ghoul::to_string(value));
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
@@ -859,10 +799,7 @@ void renderDMat3Property(Property* prop, const std::string& ownerName,
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
executeSetPropertyScript(
|
||||
p->fullyQualifiedIdentifier(),
|
||||
ghoul::to_string(value)
|
||||
);
|
||||
executeSetPropertyScript(p->fullyQualifiedIdentifier(), ghoul::to_string(value));
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
@@ -934,10 +871,7 @@ void renderDMat4Property(Property* prop, const std::string& ownerName,
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
executeSetPropertyScript(
|
||||
p->fullyQualifiedIdentifier(),
|
||||
ghoul::to_string(value)
|
||||
);
|
||||
executeSetPropertyScript(p->fullyQualifiedIdentifier(), ghoul::to_string(value));
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
@@ -143,11 +143,9 @@ bool DataCygnet::updateTexture() {
|
||||
ghoul::opengl::Texture::WrappingMode::ClampToEdge
|
||||
);
|
||||
|
||||
if (texture) {
|
||||
texture->uploadTexture();
|
||||
texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
||||
_textures[option] = std::move(texture);
|
||||
}
|
||||
texture->uploadTexture();
|
||||
texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
||||
_textures[option] = std::move(texture);
|
||||
}
|
||||
else {
|
||||
_textures[option]->setPixelData(values);
|
||||
|
||||
@@ -99,7 +99,7 @@ void DataProcessorText::addDataValues(const std::string& data,
|
||||
|
||||
// for each data point
|
||||
while (getline(memorystream, line)) {
|
||||
if (line.find("#") == 0) {
|
||||
if (!line.empty() && line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ std::vector<float*> DataProcessorText::processData(const std::string& data,
|
||||
|
||||
int numValues = 0;
|
||||
while (getline(memorystream, line)) {
|
||||
if (line.find("#") == 0) {
|
||||
if (!line.empty() && line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ void KameleonVolumeToRawTask::perform(const Task::ProgressCallback& progressCall
|
||||
|
||||
std::array<std::string, 3> variables = reader.gridVariableNames();
|
||||
|
||||
if (variables.size() == 3 && _autoDomainBounds) {
|
||||
if (_autoDomainBounds) {
|
||||
_lowerDomainBound = glm::vec3(
|
||||
reader.minValue(variables[0]),
|
||||
reader.minValue(variables[1]),
|
||||
|
||||
@@ -43,6 +43,7 @@ set(HEADER_FILES
|
||||
include/topics/shortcuttopic.h
|
||||
include/topics/subscriptiontopic.h
|
||||
include/topics/timetopic.h
|
||||
include/topics/skybrowsertopic.h
|
||||
include/topics/topic.h
|
||||
include/topics/triggerpropertytopic.h
|
||||
include/topics/versiontopic.h
|
||||
@@ -67,6 +68,7 @@ set(SOURCE_FILES
|
||||
src/topics/shortcuttopic.cpp
|
||||
src/topics/subscriptiontopic.cpp
|
||||
src/topics/timetopic.cpp
|
||||
src/topics/skybrowsertopic.cpp
|
||||
src/topics/topic.cpp
|
||||
src/topics/triggerpropertytopic.cpp
|
||||
src/topics/versiontopic.cpp
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
set(DEFAULT_MODULE ON)
|
||||
|
||||
set(OPENSPACE_DEPENDENCIES
|
||||
skybrowser
|
||||
)
|
||||
|
||||
@@ -39,14 +39,20 @@ using TopicId = size_t;
|
||||
|
||||
class Topic;
|
||||
|
||||
class Connection {
|
||||
// @TODO (abock, 2022-05-06) This is not really elegant as there is no need for a
|
||||
// Connection to be held by a shared_ptr, but there was a problem with the LuaScriptTopic
|
||||
// otherwise (issue #1940).
|
||||
// The problem there is that the LuaScriptTopic is keeping a copy of the _connection in
|
||||
// its lambda to return a script back to the caller. The script is only queued, so is
|
||||
// executed a bit longer. If the UI gets reloaded in between the creation of the lambda
|
||||
// and the execution, the _connection will be an invalid pointer and the program will
|
||||
// crash. Making this a shared_ptr circumvents that problem my having the lamdba retain
|
||||
// ownership of the _connection and keeping it alive until the message is sent. The
|
||||
// message doesn't go anywhere since noone is listening, but it's better than a crash.
|
||||
class Connection : public std::enable_shared_from_this<Connection> {
|
||||
public:
|
||||
Connection(
|
||||
std::unique_ptr<ghoul::io::Socket> s,
|
||||
std::string address,
|
||||
bool authorized = false,
|
||||
const std::string& password = ""
|
||||
);
|
||||
Connection(std::unique_ptr<ghoul::io::Socket> s, std::string address,
|
||||
bool authorized = false, const std::string& password = "");
|
||||
|
||||
void handleMessage(const std::string& message);
|
||||
void sendMessage(const std::string& message);
|
||||
|
||||
@@ -31,9 +31,6 @@ namespace openspace {
|
||||
|
||||
class LuaScriptTopic : public Topic {
|
||||
public:
|
||||
LuaScriptTopic() = default;
|
||||
virtual ~LuaScriptTopic() = default;
|
||||
|
||||
void handleJson(const nlohmann::json& json) override;
|
||||
bool isDone() const override;
|
||||
|
||||
|
||||
56
modules/server/include/topics/skybrowsertopic.h
Normal file
56
modules/server/include/topics/skybrowsertopic.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_SERVER___SKY_BROWSER_TOPIC___H__
|
||||
#define __OPENSPACE_MODULE_SERVER___SKY_BROWSER_TOPIC___H__
|
||||
|
||||
#include <modules/server/include/topics/topic.h>
|
||||
#include <chrono>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class SkyBrowserTopic : public Topic {
|
||||
public:
|
||||
SkyBrowserTopic();
|
||||
virtual ~SkyBrowserTopic();
|
||||
|
||||
void handleJson(const nlohmann::json& json) override;
|
||||
bool isDone() const override;
|
||||
|
||||
private:
|
||||
const int UnsetOnChangeHandle = -1;
|
||||
|
||||
void sendBrowserData();
|
||||
|
||||
int _targetDataCallbackHandle = UnsetOnChangeHandle;
|
||||
bool _isDone = false;
|
||||
std::chrono::system_clock::time_point _lastUpdateTime;
|
||||
std::string _lastUpdateJsonString;
|
||||
|
||||
std::chrono::milliseconds _skyBrowserUpdateTime = std::chrono::milliseconds(100);
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_SERVER___SKY_BROWSER_TOPIC___H__
|
||||
@@ -33,10 +33,9 @@ class Connection;
|
||||
|
||||
class Topic {
|
||||
public:
|
||||
Topic() {};
|
||||
virtual ~Topic();
|
||||
virtual ~Topic() = default;
|
||||
|
||||
void initialize(Connection* connection, size_t topicId);
|
||||
void initialize(std::shared_ptr<Connection> connection, size_t topicId);
|
||||
nlohmann::json wrappedPayload(const nlohmann::json& payload) const;
|
||||
nlohmann::json wrappedError(std::string message = "Could not complete request.",
|
||||
int code = 500);
|
||||
@@ -45,7 +44,7 @@ public:
|
||||
|
||||
protected:
|
||||
size_t _topicId = 0;
|
||||
Connection* _connection;
|
||||
std::shared_ptr<Connection> _connection;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -72,6 +72,10 @@ ServerInterface* ServerModule::serverInterfaceByIdentifier(const std::string& id
|
||||
return si->get();
|
||||
}
|
||||
|
||||
int ServerModule::skyBrowserUpdateTime() const {
|
||||
return _skyBrowserUpdateTime;
|
||||
}
|
||||
|
||||
void ServerModule::internalInitialize(const ghoul::Dictionary& configuration) {
|
||||
global::callback::preSync->emplace_back([this]() {
|
||||
ZoneScopedN("ServerModule")
|
||||
@@ -110,6 +114,11 @@ void ServerModule::internalInitialize(const ghoul::Dictionary& configuration) {
|
||||
_interfaces.push_back(std::move(serverInterface));
|
||||
}
|
||||
}
|
||||
if (configuration.hasValue<double>("SkyBrowserUpdateTime")) {
|
||||
_skyBrowserUpdateTime = static_cast<int>(
|
||||
configuration.value<double>("SkyBrowserUpdateTime")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerModule::preSync() {
|
||||
@@ -207,7 +216,7 @@ void ServerModule::handleConnection(std::shared_ptr<Connection> connection) {
|
||||
messageString.reserve(256);
|
||||
while (connection->socket()->getMessage(messageString)) {
|
||||
std::lock_guard lock(_messageQueueMutex);
|
||||
_messageQueue.push_back({ connection, std::move(messageString) });
|
||||
_messageQueue.push_back({ connection, messageString });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@ public:
|
||||
|
||||
ServerInterface* serverInterfaceByIdentifier(const std::string& identifier);
|
||||
|
||||
int skyBrowserUpdateTime() const;
|
||||
|
||||
protected:
|
||||
void internalInitialize(const ghoul::Dictionary& configuration) override;
|
||||
|
||||
@@ -76,6 +78,7 @@ private:
|
||||
std::vector<ConnectionData> _connections;
|
||||
std::vector<std::unique_ptr<ServerInterface>> _interfaces;
|
||||
properties::PropertyOwner _interfaceOwner;
|
||||
int _skyBrowserUpdateTime = 100;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <modules/server/include/topics/sessionrecordingtopic.h>
|
||||
#include <modules/server/include/topics/setpropertytopic.h>
|
||||
#include <modules/server/include/topics/shortcuttopic.h>
|
||||
#include <modules/server/include/topics/skybrowsertopic.h>
|
||||
#include <modules/server/include/topics/subscriptiontopic.h>
|
||||
#include <modules/server/include/topics/timetopic.h>
|
||||
#include <modules/server/include/topics/topic.h>
|
||||
@@ -69,14 +70,13 @@ namespace {
|
||||
constexpr const char* TriggerPropertyTopicKey = "trigger";
|
||||
constexpr const char* BounceTopicKey = "bounce";
|
||||
constexpr const char* FlightControllerTopicKey = "flightcontroller";
|
||||
constexpr const char* SkyBrowserKey = "skybrowser";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
Connection::Connection(std::unique_ptr<ghoul::io::Socket> s,
|
||||
std::string address,
|
||||
bool authorized,
|
||||
const std::string& password)
|
||||
Connection::Connection(std::unique_ptr<ghoul::io::Socket> s, std::string address,
|
||||
bool authorized, const std::string& password)
|
||||
: _socket(std::move(s))
|
||||
, _address(std::move(address))
|
||||
, _isAuthorized(authorized)
|
||||
@@ -109,6 +109,7 @@ Connection::Connection(std::unique_ptr<ghoul::io::Socket> s,
|
||||
_topicFactory.registerClass<BounceTopic>(BounceTopicKey);
|
||||
_topicFactory.registerClass<FlightControllerTopic>(FlightControllerTopicKey);
|
||||
_topicFactory.registerClass<VersionTopic>(VersionTopicKey);
|
||||
_topicFactory.registerClass<SkyBrowserTopic>(SkyBrowserKey);
|
||||
}
|
||||
|
||||
void Connection::handleMessage(const std::string& message) {
|
||||
@@ -118,14 +119,16 @@ void Connection::handleMessage(const std::string& message) {
|
||||
nlohmann::json j = nlohmann::json::parse(message.c_str());
|
||||
try {
|
||||
handleJson(j);
|
||||
} catch (const std::domain_error& e) {
|
||||
}
|
||||
catch (const std::domain_error& e) {
|
||||
LERROR(fmt::format("JSON handling error from: {}. {}", message, e.what()));
|
||||
}
|
||||
} catch (const std::out_of_range& e) {
|
||||
LERROR(fmt::format("JSON handling error from: {}. {}", message, e.what()));
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LERROR(e.what());
|
||||
}
|
||||
catch (const std::out_of_range& e) {
|
||||
LERROR(fmt::format("JSON handling error from: {}. {}", message, e.what()));
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LERROR(e.what());
|
||||
} catch (...) {
|
||||
if (!isAuthorized()) {
|
||||
_socket->disconnect();
|
||||
@@ -174,10 +177,7 @@ void Connection::handleJson(const nlohmann::json& json) {
|
||||
// The topic id is not registered: Initialize a new topic.
|
||||
auto typeJson = json.find(MessageKeyType);
|
||||
if (typeJson == json.end() || !typeJson->is_string()) {
|
||||
LERROR(fmt::format(
|
||||
"A type must be specified (`{}`) as a string when "
|
||||
"a new topic is initialized", MessageKeyType
|
||||
));
|
||||
LERROR("Type must be specified as a string when a new topic is initialized");
|
||||
return;
|
||||
}
|
||||
std::string type = *typeJson;
|
||||
@@ -188,7 +188,7 @@ void Connection::handleJson(const nlohmann::json& json) {
|
||||
}
|
||||
|
||||
std::unique_ptr<Topic> topic = std::unique_ptr<Topic>(_topicFactory.create(type));
|
||||
topic->initialize(this, topicId);
|
||||
topic->initialize(shared_from_this(), topicId);
|
||||
topic->handleJson(*payloadJson);
|
||||
if (!topic->isDone()) {
|
||||
_topics.emplace(topicId, std::move(topic));
|
||||
@@ -200,7 +200,7 @@ void Connection::handleJson(const nlohmann::json& json) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dispatch the message to the existing topic.
|
||||
// Dispatch the message to the existing topic
|
||||
Topic& topic = *topicIt->second;
|
||||
topic.handleJson(*payloadJson);
|
||||
if (topic.isDone()) {
|
||||
|
||||
@@ -182,7 +182,8 @@ void LuaScriptTopic::runScript(std::string script, bool shouldReturn) {
|
||||
callback = [this](ghoul::Dictionary data) {
|
||||
if (_connection) {
|
||||
nlohmann::json j = data;
|
||||
_connection->sendJson(wrappedPayload(j));
|
||||
nlohmann::json payload = wrappedPayload(j);
|
||||
_connection->sendJson(payload);
|
||||
_waitingForReturnValue = false;
|
||||
}
|
||||
};
|
||||
|
||||
131
modules/server/src/topics/skybrowsertopic.cpp
Normal file
131
modules/server/src/topics/skybrowsertopic.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "modules/server/include/topics/skybrowsertopic.h"
|
||||
|
||||
#include <modules/server/include/connection.h>
|
||||
#include <modules/server/servermodule.h>
|
||||
#include <modules/skybrowser/skybrowsermodule.h>
|
||||
#include <modules/skybrowser/include/targetbrowserpair.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/properties/property.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* EventKey = "event";
|
||||
constexpr const char* SubscribeEvent = "start_subscription";
|
||||
constexpr const char* UnsubscribeEvent = "stop_subscription";
|
||||
} // namespace
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
namespace openspace {
|
||||
|
||||
SkyBrowserTopic::SkyBrowserTopic()
|
||||
: _lastUpdateTime(std::chrono::system_clock::now())
|
||||
{
|
||||
ServerModule* module = global::moduleEngine->module<ServerModule>();
|
||||
if (module) {
|
||||
_skyBrowserUpdateTime = std::chrono::milliseconds(module->skyBrowserUpdateTime());
|
||||
}
|
||||
}
|
||||
|
||||
SkyBrowserTopic::~SkyBrowserTopic() {
|
||||
if (_targetDataCallbackHandle != UnsetOnChangeHandle) {
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
if (module) {
|
||||
module->removePreSyncCallback(_targetDataCallbackHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SkyBrowserTopic::isDone() const {
|
||||
return _isDone;
|
||||
}
|
||||
|
||||
void SkyBrowserTopic::handleJson(const nlohmann::json& json) {
|
||||
std::string event = json.at(EventKey).get<std::string>();
|
||||
if (event == UnsubscribeEvent) {
|
||||
_isDone = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event != SubscribeEvent) {
|
||||
_isDone = true;
|
||||
return;
|
||||
}
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
_targetDataCallbackHandle = module->addPreSyncCallback(
|
||||
[this]() {
|
||||
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
|
||||
if (now - _lastUpdateTime > _skyBrowserUpdateTime) {
|
||||
sendBrowserData();
|
||||
_lastUpdateTime = std::chrono::system_clock::now();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void SkyBrowserTopic::sendBrowserData() {
|
||||
using namespace openspace;
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
ghoul::Dictionary data;
|
||||
|
||||
// Set general data
|
||||
data.setValue("selectedBrowserId", module->selectedBrowserId());
|
||||
data.setValue("cameraInSolarSystem", module->isCameraInSolarSystem());
|
||||
|
||||
// Pass data for all the browsers and the corresponding targets
|
||||
if (module->isCameraInSolarSystem()) {
|
||||
const std::vector<std::unique_ptr<TargetBrowserPair>>& pairs = module->getPairs();
|
||||
ghoul::Dictionary targets;
|
||||
for (const std::unique_ptr<TargetBrowserPair>& pair : pairs) {
|
||||
std::string id = pair->browserId();
|
||||
ghoul::Dictionary target = pair->dataAsDictionary();
|
||||
targets.setValue(id, target);
|
||||
}
|
||||
data.setValue("browsers", targets);
|
||||
}
|
||||
|
||||
std::string jsonString = ghoul::formatJson(data);
|
||||
|
||||
// Only send message if data actually changed
|
||||
if (jsonString != _lastUpdateJsonString) {
|
||||
json jsonData = json::parse(jsonString.begin(), jsonString.end());
|
||||
_connection->sendJson(wrappedPayload(jsonData));
|
||||
}
|
||||
|
||||
// @TODO (2022-04-28, emmbr) The message is still sent very often; every time the
|
||||
// camera moves or the time is changes, because this changes the "roll" parameter
|
||||
// of the browser. This is the update that occurs most often. Maybe it could be
|
||||
// separated into it's own topic?
|
||||
|
||||
_lastUpdateJsonString = jsonString;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
@@ -30,12 +30,8 @@
|
||||
|
||||
namespace openspace {
|
||||
|
||||
Topic::~Topic() {
|
||||
_connection = nullptr;
|
||||
}
|
||||
|
||||
void Topic::initialize(Connection* connection, size_t topicId) {
|
||||
_connection = connection;
|
||||
void Topic::initialize(std::shared_ptr<Connection> connection, size_t topicId) {
|
||||
_connection = std::move(connection);
|
||||
_topicId = topicId;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,9 +51,15 @@ set(SOURCE_FILES
|
||||
)
|
||||
source_group("Source Files" FILES ${SOURCE_FILES})
|
||||
|
||||
set(SHADER_FILES
|
||||
shaders/target_fs.glsl
|
||||
shaders/target_vs.glsl
|
||||
)
|
||||
source_group("Shader Files" FILES ${SHADER_FILES})
|
||||
|
||||
create_new_module(
|
||||
"SkyBrowser"
|
||||
skybrowser_module
|
||||
STATIC
|
||||
${HEADER_FILES} ${SOURCE_FILES}
|
||||
${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES}
|
||||
)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
set(DEFAULT_MODULE ON)
|
||||
|
||||
set(OPENSPACE_DEPENDENCIES
|
||||
webbrowser
|
||||
webgui
|
||||
|
||||
@@ -86,6 +86,10 @@ protected:
|
||||
|
||||
void executeJavascript(const std::string& script) const;
|
||||
|
||||
bool _isUrlDirty = false;
|
||||
bool _isDimensionsDirty = false;
|
||||
bool _shouldReload = false;
|
||||
|
||||
private:
|
||||
class RenderHandler : public WebRenderHandler {
|
||||
public:
|
||||
@@ -98,10 +102,6 @@ private:
|
||||
std::unique_ptr<BrowserInstance> _browserInstance;
|
||||
CefRefPtr<RenderHandler> _renderHandler;
|
||||
CefRefPtr<WebKeyboardHandler> _keyboardHandler;
|
||||
|
||||
bool _isUrlDirty = false;
|
||||
bool _isDimensionsDirty = false;
|
||||
bool _shouldReload = false;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -46,31 +46,27 @@ public:
|
||||
void bindTexture() override;
|
||||
|
||||
glm::ivec3 borderColor() const;
|
||||
float opacity() const;
|
||||
double animationSpeed() const;
|
||||
double stopAnimationThreshold() const;
|
||||
|
||||
void setDimensions(glm::vec2 dimensions);
|
||||
void setRatio(float ratio);
|
||||
void setColor(glm::ivec3 color);
|
||||
void setOpacity(float opacity);
|
||||
void setVerticalFov(double fov);
|
||||
|
||||
// Display
|
||||
void highlight(const glm::ivec3& addition);
|
||||
void removeHighlight(const glm::ivec3& removal);
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
// Properties
|
||||
properties::FloatProperty _crossHairSize;
|
||||
properties::FloatProperty _showRectangleThreshold;
|
||||
properties::FloatProperty _lineWidth;
|
||||
properties::DoubleProperty _stopAnimationThreshold;
|
||||
properties::DoubleProperty _animationSpeed;
|
||||
|
||||
double _verticalFov = 10.0;
|
||||
|
||||
glm::ivec3 _borderColor = glm::ivec3(230);
|
||||
glm::vec2 _dimensions = glm::vec2(1.f);
|
||||
float _ratio = 1.f;
|
||||
};
|
||||
} // namespace openspace
|
||||
|
||||
|
||||
@@ -47,37 +47,40 @@ public:
|
||||
void update() override;
|
||||
|
||||
float opacity() const;
|
||||
glm::vec2 size() const;
|
||||
glm::dvec2 fineTuneVector(const glm::dvec2& drag);
|
||||
bool isInitialized() const;
|
||||
|
||||
void setVerticalFovWithScroll(float scroll);
|
||||
void setOpacity(float opacity);
|
||||
void setScreenSpaceSize(glm::vec2 newSize);
|
||||
void updateScreenSpaceSize();
|
||||
|
||||
glm::dvec2 fineTuneVector(const glm::dvec2& drag);
|
||||
void setRatio(float ratio);
|
||||
void setIdInBrowser() const;
|
||||
void setIsInitialized(bool isInitialized);
|
||||
|
||||
void updateTextureResolution();
|
||||
|
||||
// Copies rendered
|
||||
void addRenderCopy(const glm::vec3& raePosition, int nCopies);
|
||||
void removeRenderCopy();
|
||||
std::vector<std::pair<std::string, glm::dvec3>> renderCopies() const;
|
||||
void moveRenderCopy(int i, glm::vec3 raePosition);
|
||||
void addDisplayCopy(const glm::vec3& raePosition, int nCopies);
|
||||
void removeDisplayCopy();
|
||||
std::vector<std::pair<std::string, glm::dvec3>> displayCopies() const;
|
||||
std::vector<std::pair<std::string, bool>> showDisplayCopies() const;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
properties::FloatProperty _textureQuality;
|
||||
properties::BoolProperty _renderOnlyOnMaster;
|
||||
std::vector<std::unique_ptr<properties::Vec3Property>> _renderCopies;
|
||||
properties::BoolProperty _isHidden;
|
||||
std::vector<std::unique_ptr<properties::Vec3Property>> _displayCopies;
|
||||
std::vector<std::unique_ptr<properties::BoolProperty>> _showDisplayCopies;
|
||||
|
||||
void bindTexture() override;
|
||||
|
||||
// Flags
|
||||
bool _isSyncedWithWwt = false;
|
||||
bool _textureDimensionsIsDirty = false;
|
||||
bool _sizeIsDirty = false;
|
||||
bool _ratioIsDirty = false;
|
||||
bool _isInitialized = false;
|
||||
|
||||
glm::vec2 _size = glm::vec2(1.f, 1.f);
|
||||
float _ratio = 1.f;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <deque>
|
||||
|
||||
namespace ghoul { class Dictionary; }
|
||||
|
||||
namespace openspace {
|
||||
|
||||
struct ImageData;
|
||||
@@ -44,14 +46,13 @@ public:
|
||||
|
||||
// Target & Browser
|
||||
void initialize();
|
||||
// Highlighting
|
||||
void removeHighlight(const glm::ivec3& color);
|
||||
void highlight(const glm::ivec3& color);
|
||||
|
||||
// Animation
|
||||
void startAnimation(glm::dvec3 coordsEnd, double fovEnd);
|
||||
void incrementallyAnimateToCoordinate();
|
||||
void startFading(float goal, float fadeTime);
|
||||
void incrementallyFade();
|
||||
void stopAnimations();
|
||||
|
||||
// Mouse interaction
|
||||
void startFinetuningTarget();
|
||||
void fineTuneTarget(const glm::vec2& startMouse, const glm::vec2& translation);
|
||||
@@ -60,25 +61,25 @@ public:
|
||||
// Browser
|
||||
void sendIdToBrowser() const;
|
||||
void updateBrowserSize();
|
||||
std::vector<std::pair<std::string, glm::dvec3>> renderCopies() const;
|
||||
std::vector<std::pair<std::string, glm::dvec3>> displayCopies() const;
|
||||
bool isImageCollectionLoaded();
|
||||
|
||||
// Target
|
||||
void centerTargetOnScreen();
|
||||
double targetRoll();
|
||||
double targetRoll() const;
|
||||
|
||||
bool hasFinishedFading() const;
|
||||
bool isFacingCamera() const;
|
||||
bool isUsingRadiusAzimuthElevation() const;
|
||||
bool isEnabled() const;
|
||||
|
||||
void setEnabled(bool enable);
|
||||
void setOpacity(float opacity);
|
||||
void setIsSyncedWithWwt(bool isSynced);
|
||||
void setVerticalFov(double vfov);
|
||||
void setEquatorialAim(const glm::dvec2& aim);
|
||||
void setBorderColor(const glm::ivec3& color);
|
||||
void setScreenSpaceSize(const glm::vec2& dimensions);
|
||||
void setBrowserRatio(float ratio);
|
||||
void setVerticalFovWithScroll(float scroll);
|
||||
void setImageCollectionIsLoaded(bool isLoaded);
|
||||
|
||||
double verticalFov() const;
|
||||
glm::ivec3 borderColor() const;
|
||||
@@ -88,19 +89,22 @@ public:
|
||||
std::string browserId() const;
|
||||
std::string targetRenderableId() const;
|
||||
std::string targetNodeId() const;
|
||||
glm::vec2 size() const;
|
||||
float browserRatio() const;
|
||||
|
||||
SceneGraphNode* targetNode() const;
|
||||
ScreenSpaceSkyBrowser* browser() const;
|
||||
const std::deque<int>& selectedImages() const;
|
||||
std::vector<int> selectedImages() const;
|
||||
|
||||
ghoul::Dictionary dataAsDictionary() const;
|
||||
|
||||
// WorldWide Telescope image handling
|
||||
void setImageOrder(int i, int order);
|
||||
void selectImage(const ImageData& image, int i);
|
||||
void addImageLayerToWwt(const std::string& url, int i);
|
||||
void removeSelectedImage(int i);
|
||||
void loadImageCollection(const std::string& collection);
|
||||
void setImageOpacity(int i, float opacity);
|
||||
void hideChromeInterface(bool shouldHide);
|
||||
void hideChromeInterface();
|
||||
|
||||
friend bool operator==(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs);
|
||||
friend bool operator!=(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs);
|
||||
@@ -114,19 +118,13 @@ private:
|
||||
SceneGraphNode* _targetNode = nullptr;
|
||||
|
||||
// Animation
|
||||
skybrowser::Animation<float> _fadeBrowser = skybrowser::Animation(0.f, 0.f, 0.f);
|
||||
skybrowser::Animation<float> _fadeTarget = skybrowser::Animation(0.f, 0.f, 0.f);
|
||||
skybrowser::Animation<double> _fovAnimation = skybrowser::Animation(0.0, 0.0, 0.0);
|
||||
skybrowser::Animation<glm::dvec3> _moveTarget =
|
||||
skybrowser::Animation<glm::dvec3> _targetAnimation =
|
||||
skybrowser::Animation(glm::dvec3(0.0), glm::dvec3(0.0), 0.0);
|
||||
bool _targetIsAnimating = false;
|
||||
|
||||
// Dragging
|
||||
glm::dvec3 _startTargetPosition = glm::dvec3(0.0);
|
||||
|
||||
glm::dvec2 _equatorialAim = glm::dvec2(0.0);
|
||||
glm::ivec3 _borderColor = glm::ivec3(255);
|
||||
glm::vec2 _dimensions = glm::vec2(0.5f);
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -207,21 +207,21 @@ public:
|
||||
{
|
||||
_animationTime = std::chrono::milliseconds(static_cast<int>(time * 1000));
|
||||
}
|
||||
|
||||
|
||||
void start() {
|
||||
_isStarted = true;
|
||||
_startTime = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
|
||||
void stop() {
|
||||
_isStarted = false;
|
||||
}
|
||||
|
||||
|
||||
bool isAnimating() const {
|
||||
bool timeLeft = timeSpent().count() < _animationTime.count() ? true : false;
|
||||
return timeLeft && _isStarted;
|
||||
}
|
||||
|
||||
|
||||
T getNewValue();
|
||||
glm::dmat4 getRotationMatrix();
|
||||
|
||||
@@ -231,20 +231,11 @@ private:
|
||||
std::chrono::duration<double, std::milli> timeSpent = now - _startTime;
|
||||
return timeSpent;
|
||||
}
|
||||
|
||||
|
||||
double percentageSpent() const {
|
||||
return timeSpent().count() / _animationTime.count();
|
||||
}
|
||||
|
||||
double easeOutExpo(double x) {
|
||||
double epsilon = std::numeric_limits<double>::epsilon();
|
||||
return std::abs(x - 1.0) < epsilon ? 1.0 : 1.0 - pow(2.0, -10.0 * x);
|
||||
}
|
||||
|
||||
double easeInOutSine(double x) {
|
||||
return -(cos(glm::pi<double>() * x) - 1.0) / 2.0;
|
||||
}
|
||||
|
||||
// Animation
|
||||
bool _isStarted = false;
|
||||
double _lastPercentage = 0;
|
||||
|
||||
@@ -44,42 +44,42 @@ public:
|
||||
void update();
|
||||
|
||||
// WorldWide Telescope communication
|
||||
void displayImage(const std::string& url, int i);
|
||||
void selectImage(const std::string& url, int i);
|
||||
void addImageLayerToWwt(const std::string& url, int i);
|
||||
void removeSelectedImage(int i);
|
||||
void setImageOrder(int i, int order);
|
||||
void loadImageCollection(const std::string& collection);
|
||||
void setImageOpacity(int i, float opacity) const;
|
||||
void hideChromeInterface(bool shouldHide) const;
|
||||
void setImageOpacity(int i, float opacity);
|
||||
void hideChromeInterface() const;
|
||||
|
||||
bool isImageCollectionLoaded() const;
|
||||
|
||||
bool hasLoadedImages() const;
|
||||
double verticalFov() const;
|
||||
glm::ivec3 borderColor() const;
|
||||
glm::dvec2 equatorialAim() const;
|
||||
glm::dvec2 fieldsOfView() const;
|
||||
const std::deque<int>& getSelectedImages() const;
|
||||
std::vector<int> selectedImages() const;
|
||||
std::vector<double> opacities() const;
|
||||
|
||||
void setHasLoadedImages(bool isLoaded);
|
||||
void setImageCollectionIsLoaded(bool isLoaded);
|
||||
void setVerticalFov(double vfov);
|
||||
void setIsSyncedWithWwt(bool isSynced);
|
||||
void setEquatorialAim(glm::dvec2 equatorial);
|
||||
void setBorderColor(glm::ivec3 color);
|
||||
void setTargetRoll(double roll);
|
||||
|
||||
void highlight(const glm::ivec3& addition) const;
|
||||
// The removal parameter decides what will be removed from the border color
|
||||
void removeHighlight(const glm::ivec3& removal) const;
|
||||
void updateBorderColor() const;
|
||||
void updateAim() const;
|
||||
|
||||
protected:
|
||||
void setIdInBrowser(const std::string& id) const;
|
||||
std::deque<std::pair<int, double>>::iterator findSelectedImage(int i);
|
||||
|
||||
double _verticalFov = 10.0f;
|
||||
glm::ivec3 _borderColor = glm::ivec3(70);
|
||||
glm::dvec2 _equatorialAim = glm::dvec2(0.0);
|
||||
double _targetRoll = 0.0;
|
||||
bool _hasLoadedImages = false;
|
||||
std::deque<int> _selectedImages;
|
||||
bool _isImageCollectionLoaded = false;
|
||||
std::deque<std::pair<int, double>> _selectedImages;
|
||||
|
||||
private:
|
||||
void setWebpageBorderColor(glm::ivec3 color) const;
|
||||
@@ -96,7 +96,6 @@ private:
|
||||
ghoul::Dictionary setImageOpacityMessage(const std::string& id, double opacity) const;
|
||||
ghoul::Dictionary setLayerOrderMessage(const std::string& id, int version);
|
||||
|
||||
bool _isSyncedWithWwt = false;
|
||||
bool _borderColorIsDirty = false;
|
||||
bool _equatorialAimIsDirty = false;
|
||||
int messageCounter = 0;
|
||||
|
||||
@@ -32,12 +32,12 @@ in vec4 vs_position;
|
||||
uniform float crossHairSize;
|
||||
uniform bool showRectangle;
|
||||
uniform float lineWidth;
|
||||
uniform vec2 dimensions;
|
||||
uniform float ratio;
|
||||
uniform vec4 lineColor;
|
||||
uniform float fov;
|
||||
|
||||
uniform bool additiveBlending;
|
||||
uniform float opacity = 1.0;
|
||||
uniform float opacity;
|
||||
uniform vec3 multiplyColor;
|
||||
|
||||
// A factor which states how much thicker vertical lines are rendered than horizontal
|
||||
@@ -67,23 +67,22 @@ float createCrosshair(in float linewidth, in float ratio, in vec2 coord) {
|
||||
#include "fragment.glsl"
|
||||
|
||||
Fragment getFragment() {
|
||||
float ratio = dimensions.y / dimensions.x;
|
||||
float rectangle = 0.0;
|
||||
float maxWwtFov = 70;
|
||||
|
||||
float crosshair = createCrosshair(lineWidth, ratio, vs_st);
|
||||
float crossHairHeight = crossHairSize/maxWwtFov;
|
||||
float crossHairWidth = crossHairHeight * ratio;
|
||||
float crossHairBox = createFilledRectangle(crossHairHeight, crossHairWidth, vs_st);
|
||||
float crossHairBox = createFilledRectangle(crossHairWidth, crossHairHeight, vs_st);
|
||||
crosshair *= crossHairBox;
|
||||
|
||||
if (showRectangle) {
|
||||
float height = (fov * 0.5)/maxWwtFov;
|
||||
float width = height * ratio;
|
||||
float outerEdge = createFilledRectangle(height, width, vs_st);
|
||||
float lineWidthX = lineWidth * 2 * VerticalThickness;
|
||||
float lineWidthY = lineWidth * 2;
|
||||
float innerEdge = createFilledRectangle(height-lineWidthX, width-lineWidthY, vs_st);
|
||||
float height = ((fov * 0.5)/maxWwtFov)-lineWidthX;
|
||||
float width = (height * ratio) - lineWidthY;
|
||||
float outerEdge = createFilledRectangle(width, height, vs_st);
|
||||
float innerEdge = createFilledRectangle(width-lineWidthY, height-lineWidthX, vs_st);
|
||||
rectangle = outerEdge - innerEdge;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,21 @@
|
||||
#include "skybrowsermodule_lua.inl"
|
||||
|
||||
namespace {
|
||||
constexpr const openspace::properties::Property::PropertyInfo EnabledInfo = {
|
||||
"Enabled",
|
||||
"Enabled",
|
||||
"Decides if the GUI for this module should be enabled."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo
|
||||
ShowTitleInGuiBrowserInfo =
|
||||
{
|
||||
"ShowTitleInGuiBrowser",
|
||||
"Show Title in Gui Browser",
|
||||
"If true, the name of the currently selected sky browser is shown in the WebGUI "
|
||||
"browser."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo AllowRotationInfo = {
|
||||
"AllowCameraRotation",
|
||||
"Allow Camera Rotation",
|
||||
@@ -61,11 +76,41 @@ namespace {
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo BrowserSpeedInfo = {
|
||||
"BrowserAnimationSpeed",
|
||||
"Field Of View Animation Speed",
|
||||
"Field of View Animation Speed",
|
||||
"This determines the speed of the animation of the field of view in the browser."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo HideWithGuiInfo = {
|
||||
"HideTargetsBrowsersWithGui",
|
||||
"Hide Targets and Browsers with GUI",
|
||||
"If checked, the targets and browsers will be disabled when the sky browser "
|
||||
"panel is minimized."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo InverseZoomInfo = {
|
||||
"InverseZoomDirection",
|
||||
"Inverse Zoom Direction",
|
||||
"If checked, the zoom direction of the scroll over the AAS WWT browser will be "
|
||||
"inversed."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo SpaceCraftTimeInfo = {
|
||||
"SpaceCraftAnimationTime",
|
||||
"Space Craft Animation Time",
|
||||
"Sets the duration (in seconds) of the animation of the space craft when it is "
|
||||
"pointed to where the target is aiming."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo ImageCollectionInfo = {
|
||||
"WwtImageCollectionUrl",
|
||||
"AAS WorldWide Telescope Image Collection Url",
|
||||
"The url of the image collection which is loaded into AAS WorldWide Telescope."
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(SkyBrowserModule)]] Parameters {
|
||||
// [[codegen::verbatim(EnabledInfo.description)]]
|
||||
std::optional<bool> enabled;
|
||||
|
||||
// [[codegen::verbatim(AllowRotationInfo.description)]]
|
||||
std::optional<bool> allowCameraRotation;
|
||||
|
||||
@@ -77,6 +122,18 @@ namespace {
|
||||
|
||||
// [[codegen::verbatim(BrowserSpeedInfo.description)]]
|
||||
std::optional<double> browserSpeed;
|
||||
|
||||
// [[codegen::verbatim(HideWithGuiInfo.description)]]
|
||||
std::optional<bool> hideTargetsBrowsersGui;
|
||||
|
||||
// [[codegen::verbatim(InverseZoomInfo.description)]]
|
||||
std::optional<bool> inverseZoomDirection;
|
||||
|
||||
// [[codegen::verbatim(SpaceCraftTimeInfo.description)]]
|
||||
std::optional<double> spaceCraftAnimationTime;
|
||||
|
||||
// [[codegen::verbatim(SpaceCraftTimeInfo.description)]]
|
||||
std::optional<std::string> wwtImageCollectionUrl;
|
||||
};
|
||||
|
||||
#include "skybrowsermodule_codegen.cpp"
|
||||
@@ -86,15 +143,29 @@ namespace openspace {
|
||||
|
||||
SkyBrowserModule::SkyBrowserModule()
|
||||
: OpenSpaceModule(SkyBrowserModule::Name)
|
||||
, _enabled(EnabledInfo)
|
||||
, _showTitleInGuiBrowser(ShowTitleInGuiBrowserInfo, true)
|
||||
, _allowCameraRotation(AllowRotationInfo, true)
|
||||
, _cameraRotationSpeed(CameraRotSpeedInfo, 0.5, 0.0, 1.0)
|
||||
, _targetAnimationSpeed(TargetSpeedInfo, 0.2, 0.0, 1.0)
|
||||
, _browserAnimationSpeed(BrowserSpeedInfo, 5.0, 0.0, 10.0)
|
||||
, _hideTargetsBrowsersWithGui(HideWithGuiInfo, false)
|
||||
, _inverseZoomDirection(InverseZoomInfo, false)
|
||||
, _spaceCraftAnimationTime(SpaceCraftTimeInfo, 2.0, 0.0, 10.0)
|
||||
, _wwtImageCollectionUrl(ImageCollectionInfo,
|
||||
"https://data.openspaceproject.com/wwt/1/imagecollection.wtml")
|
||||
{
|
||||
addProperty(_enabled);
|
||||
addProperty(_showTitleInGuiBrowser);
|
||||
addProperty(_allowCameraRotation);
|
||||
addProperty(_cameraRotationSpeed);
|
||||
addProperty(_targetAnimationSpeed);
|
||||
addProperty(_browserAnimationSpeed);
|
||||
addProperty(_hideTargetsBrowsersWithGui);
|
||||
addProperty(_inverseZoomDirection);
|
||||
addProperty(_spaceCraftAnimationTime);
|
||||
addProperty(_wwtImageCollectionUrl);
|
||||
_wwtImageCollectionUrl.setReadOnly(true);
|
||||
|
||||
// Set callback functions
|
||||
global::callback::mouseButton->emplace(global::callback::mouseButton->begin(),
|
||||
@@ -108,59 +179,68 @@ SkyBrowserModule::SkyBrowserModule()
|
||||
|
||||
global::callback::preSync->emplace_back([this]() {
|
||||
constexpr double SolarSystemRadius = 30.0 * distanceconstants::AstronomicalUnit;
|
||||
|
||||
|
||||
// Disable browser and targets when camera is outside of solar system
|
||||
bool camWasInSolarSystem = _isCameraInSolarSystem;
|
||||
glm::dvec3 cameraPos = global::navigationHandler->camera()->positionVec3();
|
||||
_isCameraInSolarSystem = glm::length(cameraPos) < SolarSystemRadius;
|
||||
bool vizModeChanged = _isCameraInSolarSystem != camWasInSolarSystem;
|
||||
|
||||
// Visualization mode changed. Start fading
|
||||
if (vizModeChanged && !_isCameraInSolarSystem) {
|
||||
// Camera moved into the solar system
|
||||
_isFading = true;
|
||||
_goal = Transparency::Transparent;
|
||||
// Visualization mode changed. Start fading in/out
|
||||
if (vizModeChanged) {
|
||||
constexpr float FadeDuration = 2.f;
|
||||
|
||||
float transparency = [](Transparency goal) {
|
||||
switch (goal) {
|
||||
case Transparency::Transparent: return 0.f;
|
||||
case Transparency::Opaque: return 1.f;
|
||||
default: throw ghoul::MissingCaseException();
|
||||
if (camWasInSolarSystem) { // Camera moved out of the solar system => fade out
|
||||
for (const std::unique_ptr<TargetBrowserPair>& pair : _targetsBrowsers) {
|
||||
pair->startFading(0.f, FadeDuration);
|
||||
}
|
||||
}(_goal);
|
||||
|
||||
std::for_each(
|
||||
_targetsBrowsers.begin(),
|
||||
_targetsBrowsers.end(),
|
||||
[&](const std::unique_ptr<TargetBrowserPair>& pair) {
|
||||
pair->startFading(transparency, 2.f);
|
||||
// Also hide the hover circle
|
||||
disableHoverCircle();
|
||||
}
|
||||
else { // Camera moved into the solar system => fade in
|
||||
for (const std::unique_ptr<TargetBrowserPair>& pair : _targetsBrowsers) {
|
||||
pair->startFading(1.f, FadeDuration);
|
||||
}
|
||||
);
|
||||
}
|
||||
// Fade pairs if the camera moved in or out the solar system
|
||||
if (_isFading) {
|
||||
incrementallyFadeBrowserTargets(_goal);
|
||||
}
|
||||
}
|
||||
|
||||
if (_isCameraInSolarSystem) {
|
||||
std::for_each(
|
||||
_targetsBrowsers.begin(),
|
||||
_targetsBrowsers.end(),
|
||||
[&](const std::unique_ptr<TargetBrowserPair>& pair) {
|
||||
pair->synchronizeAim();
|
||||
}
|
||||
);
|
||||
for (const std::unique_ptr<TargetBrowserPair>& pair : _targetsBrowsers) {
|
||||
pair->synchronizeAim();
|
||||
}
|
||||
incrementallyAnimateTargets();
|
||||
}
|
||||
if (_cameraRotation.isAnimating() && _allowCameraRotation) {
|
||||
incrementallyRotateCamera();
|
||||
}
|
||||
|
||||
// Trigger callbacks (should maybe have a check to see if update is needed)
|
||||
using K = CallbackHandle;
|
||||
using V = CallbackFunction;
|
||||
for (const std::pair<const K, V>& it : _preSyncCallbacks) {
|
||||
it.second(); // call function
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) {
|
||||
const Parameters p = codegen::bake<Parameters>(dict);
|
||||
|
||||
// Register ScreenSpaceRenderable
|
||||
_enabled = p.enabled.value_or(true);
|
||||
_allowCameraRotation = p.allowCameraRotation.value_or(_allowCameraRotation);
|
||||
_cameraRotationSpeed = p.cameraRotSpeed.value_or(_cameraRotationSpeed);
|
||||
_targetAnimationSpeed = p.targetSpeed.value_or(_targetAnimationSpeed);
|
||||
_browserAnimationSpeed = p.browserSpeed.value_or(_browserAnimationSpeed);
|
||||
_inverseZoomDirection = p.inverseZoomDirection.value_or(_inverseZoomDirection);
|
||||
_wwtImageCollectionUrl = p.wwtImageCollectionUrl.value_or(_wwtImageCollectionUrl);
|
||||
_hideTargetsBrowsersWithGui = p.hideTargetsBrowsersGui.value_or(
|
||||
_hideTargetsBrowsersWithGui
|
||||
);
|
||||
_spaceCraftAnimationTime = p.spaceCraftAnimationTime.value_or(
|
||||
_spaceCraftAnimationTime
|
||||
);
|
||||
|
||||
ghoul::TemplateFactory<ScreenSpaceRenderable>* fScreenSpaceRenderable =
|
||||
FactoryManager::ref().factory<ScreenSpaceRenderable>();
|
||||
ghoul_assert(fScreenSpaceRenderable, "ScreenSpaceRenderable factory was not created");
|
||||
@@ -168,7 +248,6 @@ void SkyBrowserModule::internalInitialize(const ghoul::Dictionary& dict) {
|
||||
// Register ScreenSpaceSkyBrowser
|
||||
fScreenSpaceRenderable->registerClass<ScreenSpaceSkyBrowser>("ScreenSpaceSkyBrowser");
|
||||
|
||||
// Register ScreenSpaceRenderable
|
||||
ghoul::TemplateFactory<Renderable>* fRenderable =
|
||||
FactoryManager::ref().factory<Renderable>();
|
||||
ghoul_assert(fRenderable, "Renderable factory was not created");
|
||||
@@ -197,10 +276,11 @@ void SkyBrowserModule::addTargetBrowserPair(const std::string& targetId,
|
||||
if (browser && target) {
|
||||
_targetsBrowsers.push_back(std::make_unique<TargetBrowserPair>(target, browser));
|
||||
}
|
||||
_uniqueIdentifierCounter++;
|
||||
}
|
||||
|
||||
void SkyBrowserModule::removeTargetBrowserPair(const std::string& id) {
|
||||
TargetBrowserPair* found = getPair(id);
|
||||
TargetBrowserPair* found = pair(id);
|
||||
if (!found) {
|
||||
return;
|
||||
}
|
||||
@@ -211,18 +291,17 @@ void SkyBrowserModule::removeTargetBrowserPair(const std::string& id) {
|
||||
[&](const std::unique_ptr<TargetBrowserPair>& pair) {
|
||||
// should this be?
|
||||
// found == pair.get()
|
||||
return *found == *(pair.get());
|
||||
return found == pair.get();
|
||||
}
|
||||
);
|
||||
|
||||
_targetsBrowsers.erase(it, _targetsBrowsers.end());
|
||||
_mouseOnPair = nullptr;
|
||||
}
|
||||
|
||||
void SkyBrowserModule::lookAtTarget(const std::string& id) {
|
||||
TargetBrowserPair* pair = getPair(id);
|
||||
if (pair) {
|
||||
startRotatingCamera(pair->targetDirectionGalactic());
|
||||
TargetBrowserPair* found = pair(id);
|
||||
if (found) {
|
||||
startRotatingCamera(found->targetDirectionGalactic());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,23 +309,39 @@ void SkyBrowserModule::setHoverCircle(SceneGraphNode* circle) {
|
||||
_hoverCircle = circle;
|
||||
}
|
||||
|
||||
void SkyBrowserModule::moveHoverCircle(int i) {
|
||||
void SkyBrowserModule::moveHoverCircle(int i, bool useScript) {
|
||||
const ImageData& image = _dataHandler->getImage(i);
|
||||
|
||||
// Only move and show circle if the image has coordinates
|
||||
if (_hoverCircle && image.hasCelestialCoords && _isCameraInSolarSystem) {
|
||||
// Make circle visible
|
||||
_hoverCircle->renderable()->property("Enabled")->set(true);
|
||||
const std::string id = _hoverCircle->identifier();
|
||||
|
||||
// Show the circle
|
||||
if (useScript) {
|
||||
const std::string script = fmt::format(
|
||||
"openspace.setPropertyValueSingle('Scene.{}.Renderable.Fade', 1.0);",
|
||||
id
|
||||
);
|
||||
global::scriptEngine->queueScript(
|
||||
script,
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
else {
|
||||
Renderable* renderable = _hoverCircle->renderable();
|
||||
if (renderable) {
|
||||
renderable->property("Fade")->set(1.f);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the exact target position
|
||||
// Move it slightly outside of the celestial sphere so it doesn't overlap with
|
||||
// the target
|
||||
glm::dvec3 pos = skybrowser::equatorialToGalactic(image.equatorialCartesian);
|
||||
pos *= skybrowser::CelestialSphereRadius * 1.1;
|
||||
// Uris for properties
|
||||
std::string id = _hoverCircle->identifier();
|
||||
|
||||
std::string script = fmt::format(
|
||||
// Note that the position can only be set through the script engine
|
||||
const std::string script = fmt::format(
|
||||
"openspace.setPropertyValueSingle('Scene.{}.Translation.Position', {});",
|
||||
id, ghoul::to_string(pos)
|
||||
);
|
||||
@@ -257,9 +352,21 @@ void SkyBrowserModule::moveHoverCircle(int i) {
|
||||
}
|
||||
}
|
||||
|
||||
void SkyBrowserModule::disableHoverCircle() {
|
||||
void SkyBrowserModule::disableHoverCircle(bool useScript) {
|
||||
if (_hoverCircle && _hoverCircle->renderable()) {
|
||||
_hoverCircle->renderable()->property("Enabled")->set(false);
|
||||
if (useScript) {
|
||||
const std::string script = fmt::format(
|
||||
"openspace.setPropertyValueSingle('Scene.{}.Renderable.Fade', 0.0);",
|
||||
_hoverCircle->identifier()
|
||||
);
|
||||
global::scriptEngine->queueScript(
|
||||
script,
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
else {
|
||||
_hoverCircle->renderable()->property("Fade")->set(0.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,7 +392,7 @@ int SkyBrowserModule::nPairs() const {
|
||||
return static_cast<int>(_targetsBrowsers.size());
|
||||
}
|
||||
|
||||
TargetBrowserPair* SkyBrowserModule::getPair(const std::string& id) const {
|
||||
TargetBrowserPair* SkyBrowserModule::pair(const std::string& id) const {
|
||||
auto it = std::find_if(
|
||||
_targetsBrowsers.begin(),
|
||||
_targetsBrowsers.end(),
|
||||
@@ -296,7 +403,11 @@ TargetBrowserPair* SkyBrowserModule::getPair(const std::string& id) const {
|
||||
return foundBrowser || foundTarget || foundTargetNode;
|
||||
}
|
||||
);
|
||||
return it != _targetsBrowsers.end() ? it->get() : nullptr;
|
||||
TargetBrowserPair* found = it != _targetsBrowsers.end() ? it->get() : nullptr;
|
||||
if (found == nullptr) {
|
||||
LINFO(fmt::format("Identifier '{}' not found", id));
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
void SkyBrowserModule::startRotatingCamera(glm::dvec3 endAnimation) {
|
||||
@@ -315,29 +426,6 @@ void SkyBrowserModule::incrementallyRotateCamera() {
|
||||
}
|
||||
}
|
||||
|
||||
void SkyBrowserModule::incrementallyFadeBrowserTargets(Transparency goal) {
|
||||
bool isAllFinished = true;
|
||||
for (std::unique_ptr<TargetBrowserPair>& pair : _targetsBrowsers) {
|
||||
if (pair->isEnabled()) {
|
||||
bool isPairFinished = pair->hasFinishedFading();
|
||||
if (!isPairFinished) {
|
||||
pair->incrementallyFade();
|
||||
}
|
||||
else if (isPairFinished && goal == Transparency::Transparent) {
|
||||
pair->setEnabled(false);
|
||||
pair->setOpacity(1.0);
|
||||
|
||||
}
|
||||
isAllFinished &= isPairFinished;
|
||||
}
|
||||
}
|
||||
|
||||
// The transition is over when the fade is finished
|
||||
if (isAllFinished) {
|
||||
_isFading = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SkyBrowserModule::incrementallyAnimateTargets() {
|
||||
for (std::unique_ptr<TargetBrowserPair>& pair : _targetsBrowsers) {
|
||||
if (pair->isEnabled()) {
|
||||
@@ -354,8 +442,16 @@ double SkyBrowserModule::browserAnimationSpeed() const {
|
||||
return _browserAnimationSpeed;
|
||||
}
|
||||
|
||||
double SkyBrowserModule::spaceCraftAnimationTime() const {
|
||||
return _spaceCraftAnimationTime;
|
||||
}
|
||||
|
||||
std::string SkyBrowserModule::wwtImageCollectionUrl() const {
|
||||
return _wwtImageCollectionUrl;
|
||||
}
|
||||
|
||||
void SkyBrowserModule::setSelectedBrowser(const std::string& id) {
|
||||
TargetBrowserPair* found = getPair(id);
|
||||
TargetBrowserPair* found = pair(id);
|
||||
if (found) {
|
||||
_selectedBrowser = id;
|
||||
}
|
||||
@@ -366,12 +462,12 @@ std::string SkyBrowserModule::selectedBrowserId() const {
|
||||
}
|
||||
|
||||
std::string SkyBrowserModule::selectedTargetId() const {
|
||||
TargetBrowserPair* found = getPair(_selectedBrowser);
|
||||
TargetBrowserPair* found = pair(_selectedBrowser);
|
||||
return found ? found->targetRenderableId() : "";
|
||||
}
|
||||
|
||||
glm::ivec3 SkyBrowserModule::highlight() const {
|
||||
return _highlightAddition;
|
||||
int SkyBrowserModule::uniqueIdentifierCounter() const {
|
||||
return _uniqueIdentifierCounter;
|
||||
}
|
||||
|
||||
bool SkyBrowserModule::isCameraInSolarSystem() const {
|
||||
@@ -379,15 +475,47 @@ bool SkyBrowserModule::isCameraInSolarSystem() const {
|
||||
}
|
||||
|
||||
bool SkyBrowserModule::isSelectedPairUsingRae() const {
|
||||
TargetBrowserPair* found = getPair(_selectedBrowser);
|
||||
TargetBrowserPair* found = pair(_selectedBrowser);
|
||||
return found ? found->isUsingRadiusAzimuthElevation() : false;
|
||||
}
|
||||
|
||||
bool SkyBrowserModule::isSelectedPairFacingCamera() const {
|
||||
TargetBrowserPair* found = getPair(_selectedBrowser);
|
||||
TargetBrowserPair* found = pair(_selectedBrowser);
|
||||
return found ? found->isFacingCamera() : false;
|
||||
}
|
||||
|
||||
SkyBrowserModule::CallbackHandle SkyBrowserModule::addPreSyncCallback(
|
||||
CallbackFunction cb)
|
||||
{
|
||||
CallbackHandle handle = _nextCallbackHandle++;
|
||||
_preSyncCallbacks.emplace_back(handle, std::move(cb));
|
||||
return handle;
|
||||
}
|
||||
|
||||
void SkyBrowserModule::removePreSyncCallback(CallbackHandle handle) {
|
||||
const auto it = std::find_if(
|
||||
_preSyncCallbacks.begin(),
|
||||
_preSyncCallbacks.end(),
|
||||
[handle](const std::pair<CallbackHandle, CallbackFunction>& cb) {
|
||||
return cb.first == handle;
|
||||
}
|
||||
);
|
||||
|
||||
ghoul_assert(
|
||||
it != _preSyncCallbacks.end(),
|
||||
"handle must be a valid callback handle"
|
||||
);
|
||||
|
||||
_preSyncCallbacks.erase(it);
|
||||
}
|
||||
|
||||
std::vector<documentation::Documentation> SkyBrowserModule::documentations() const {
|
||||
return {
|
||||
RenderableSkyTarget::Documentation(),
|
||||
ScreenSpaceSkyBrowser::Documentation()
|
||||
};
|
||||
}
|
||||
|
||||
scripting::LuaLibrary SkyBrowserModule::luaLibrary() const {
|
||||
return {
|
||||
"skybrowser",
|
||||
@@ -415,12 +543,17 @@ scripting::LuaLibrary SkyBrowserModule::luaLibrary() const {
|
||||
codegen::lua::SetVerticalFov,
|
||||
codegen::lua::SetBorderColor,
|
||||
codegen::lua::TranslateScreenSpaceRenderable,
|
||||
codegen::lua::AddRenderCopy,
|
||||
codegen::lua::SetScreenSpaceSize,
|
||||
codegen::lua::RemoveRenderCopy,
|
||||
codegen::lua::AddDisplayCopy,
|
||||
codegen::lua::SetBrowserRatio,
|
||||
codegen::lua::RemoveDisplayCopy,
|
||||
codegen::lua::StartFinetuningTarget,
|
||||
codegen::lua::FinetuneTargetPosition,
|
||||
codegen::lua::ScrollOverBrowser
|
||||
codegen::lua::ScrollOverBrowser,
|
||||
codegen::lua::LoadingImageCollectionComplete,
|
||||
codegen::lua::ShowAllTargetsAndBrowsers,
|
||||
codegen::lua::PointSpaceCraft,
|
||||
codegen::lua::GetWwtImageCollectionUrl,
|
||||
codegen::lua::StopAnimations
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <openspace/util/mouse.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/doubleproperty.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <fstream>
|
||||
|
||||
namespace openspace {
|
||||
@@ -43,30 +44,21 @@ class TargetBrowserPair;
|
||||
class SceneGraphNode;
|
||||
struct ImageData;
|
||||
|
||||
enum class Transparency {
|
||||
Transparent,
|
||||
Opaque
|
||||
};
|
||||
|
||||
enum class MouseInteraction {
|
||||
Hover,
|
||||
Drag,
|
||||
FineTune
|
||||
};
|
||||
|
||||
class SkyBrowserModule : public OpenSpaceModule {
|
||||
public:
|
||||
constexpr static const char* Name = "SkyBrowser";
|
||||
using CallbackHandle = int;
|
||||
using CallbackFunction = std::function<void()>;
|
||||
|
||||
SkyBrowserModule();
|
||||
|
||||
std::vector<std::unique_ptr<TargetBrowserPair>>& getPairs();
|
||||
int nPairs() const;
|
||||
TargetBrowserPair* getPair(const std::string& id) const;
|
||||
TargetBrowserPair* pair(const std::string& id) const;
|
||||
const std::unique_ptr<WwtDataHandler>& getWwtDataHandler() const;
|
||||
std::string selectedBrowserId() const;
|
||||
std::string selectedTargetId() const;
|
||||
glm::ivec3 highlight() const;
|
||||
int uniqueIdentifierCounter() const;
|
||||
|
||||
void setSelectedBrowser(const std::string& id);
|
||||
void setHoverCircle(SceneGraphNode* circle);
|
||||
@@ -75,10 +67,11 @@ public:
|
||||
void lookAtTarget(const std::string& id);
|
||||
void startRotatingCamera(glm::dvec3 endAnimation); // Pass in galactic coordinate
|
||||
void incrementallyRotateCamera();
|
||||
void incrementallyFadeBrowserTargets(Transparency goal);
|
||||
void incrementallyAnimateTargets();
|
||||
double targetAnimationSpeed() const;
|
||||
double browserAnimationSpeed() const;
|
||||
double spaceCraftAnimationTime() const;
|
||||
std::string wwtImageCollectionUrl() const;
|
||||
|
||||
bool isCameraInSolarSystem() const;
|
||||
bool isSelectedPairFacingCamera() const;
|
||||
@@ -89,44 +82,42 @@ public:
|
||||
void addTargetBrowserPair(const std::string& targetId, const std::string& browserId);
|
||||
|
||||
// Hover circle
|
||||
void moveHoverCircle(int i);
|
||||
void disableHoverCircle();
|
||||
void moveHoverCircle(int i, bool useScript = true);
|
||||
void disableHoverCircle(bool useScript = true);
|
||||
|
||||
// Image collection handling
|
||||
void loadImages(const std::string& root, const std::filesystem::path& directory);
|
||||
int nLoadedImages() const;
|
||||
|
||||
CallbackHandle addPreSyncCallback(CallbackFunction cb);
|
||||
void removePreSyncCallback(CallbackHandle handle);
|
||||
|
||||
scripting::LuaLibrary luaLibrary() const override;
|
||||
//std::vector<documentation::Documentation> documentations() const override;
|
||||
std::vector<documentation::Documentation> documentations() const override;
|
||||
|
||||
protected:
|
||||
void internalInitialize(const ghoul::Dictionary& dict) override;
|
||||
|
||||
private:
|
||||
properties::BoolProperty _enabled;
|
||||
properties::BoolProperty _showTitleInGuiBrowser;
|
||||
properties::BoolProperty _allowCameraRotation;
|
||||
properties::BoolProperty _hideTargetsBrowsersWithGui;
|
||||
properties::BoolProperty _inverseZoomDirection;
|
||||
properties::DoubleProperty _cameraRotationSpeed;
|
||||
properties::DoubleProperty _targetAnimationSpeed;
|
||||
properties::DoubleProperty _browserAnimationSpeed;
|
||||
glm::ivec3 _highlightAddition = glm::ivec3(35); // Highlight object when mouse hovers
|
||||
properties::DoubleProperty _spaceCraftAnimationTime;
|
||||
properties::StringProperty _wwtImageCollectionUrl;
|
||||
|
||||
// The browsers and targets
|
||||
std::vector<std::unique_ptr<TargetBrowserPair>> _targetsBrowsers;
|
||||
TargetBrowserPair* _mouseOnPair = nullptr;
|
||||
SceneGraphNode* _hoverCircle = nullptr;
|
||||
std::string _selectedBrowser = ""; // Currently selected browser
|
||||
|
||||
// Fading
|
||||
Transparency _goal = Transparency::Opaque;
|
||||
int _uniqueIdentifierCounter = 0;
|
||||
|
||||
// Flags
|
||||
bool _isCameraInSolarSystem = true; // Visualization modes
|
||||
bool _isFading = false;
|
||||
|
||||
// Mouse interaction
|
||||
glm::vec2 _mousePosition; // Current mouse position in screen space coordinates
|
||||
glm::vec2 _startMousePosition;
|
||||
glm::vec2 _startDragPosition;
|
||||
glm::dvec3 _startTargetPosition;
|
||||
|
||||
// Animation of rotation of camera to look at coordinate galactic coordinates
|
||||
skybrowser::Animation<glm::dvec3> _cameraRotation =
|
||||
@@ -134,6 +125,10 @@ private:
|
||||
|
||||
// Data handler for the image collections
|
||||
std::unique_ptr<WwtDataHandler> _dataHandler;
|
||||
|
||||
// Callbacks for tiggering topic
|
||||
int _nextCallbackHandle = 0;
|
||||
std::vector<std::pair<CallbackHandle, CallbackFunction>> _preSyncCallbacks;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <modules/skybrowser/include/utility.h>
|
||||
#include <modules/skybrowser/include/targetbrowserpair.h>
|
||||
#include <modules/skybrowser/include/wwtdatahandler.h>
|
||||
#include <openspace/events/eventengine.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
@@ -44,21 +45,21 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void selectImage(int imageIndex) {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
// Load image
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
|
||||
if (module->isCameraInSolarSystem()) {
|
||||
TargetBrowserPair* selected = module->getPair(module->selectedBrowserId());
|
||||
TargetBrowserPair* selected = module->pair(module->selectedBrowserId());
|
||||
if (selected) {
|
||||
const ImageData& image = module->getWwtDataHandler()->getImage(imageIndex);
|
||||
// Load image into browser
|
||||
std::string str = image.name;
|
||||
// Check if character is ASCII - if it isn't, remove
|
||||
str.erase(
|
||||
std::remove_if(
|
||||
str.begin(), str.end(),
|
||||
[](char c) {
|
||||
// Check if character is ASCII - if it isn't, remove
|
||||
return c < 0 || c >= 128;
|
||||
}
|
||||
),
|
||||
@@ -84,7 +85,7 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void setHoverCircle(std::string identifier) {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SceneGraphNode* circle = global::renderEngine->scene()->sceneGraphNode(identifier);
|
||||
global::moduleEngine->module<SkyBrowserModule>()->setHoverCircle(circle);
|
||||
}
|
||||
@@ -94,8 +95,8 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void moveCircleToHoverImage(int imageIndex) {
|
||||
using namespace openspace;
|
||||
|
||||
global::moduleEngine->module<SkyBrowserModule>()->moveHoverCircle(imageIndex);
|
||||
|
||||
global::moduleEngine->module<SkyBrowserModule>()->moveHoverCircle(imageIndex, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,17 +104,14 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void disableHoverCircle() {
|
||||
using namespace openspace;
|
||||
|
||||
global::moduleEngine->module<SkyBrowserModule>()->disableHoverCircle();
|
||||
|
||||
global::moduleEngine->module<SkyBrowserModule>()->disableHoverCircle(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an identifier to a sky browser or a sky target, an image index and the order
|
||||
* which it should have in the selected image list. The image is then changed to have this
|
||||
* order.
|
||||
* \param id Identifier
|
||||
* \param i Image index
|
||||
* \param order Order of image
|
||||
*/
|
||||
[[codegen::luawrap]] void setImageLayerOrder(std::string identifier, int imageIndex,
|
||||
int imageOrder)
|
||||
@@ -121,7 +119,7 @@ namespace {
|
||||
using namespace openspace;
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->setImageOrder(imageIndex, imageOrder);
|
||||
}
|
||||
@@ -133,20 +131,17 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void loadImagesToWWT(std::string identifier) {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
// Load images from url
|
||||
LINFO("Connection established to WorldWide Telescope application in " + identifier);
|
||||
LINFO("Loading image collections to " + identifier);
|
||||
|
||||
// Load the collections here because we know that the browser can execute javascript
|
||||
std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/"
|
||||
"wwt-web-client/master/assets/webclient-explore-root.wtml";
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->hideChromeInterface(true);
|
||||
pair->loadImageCollection(root);
|
||||
pair->hideChromeInterface();
|
||||
pair->loadImageCollection(module->wwtImageCollectionUrl());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +151,7 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void startSetup() {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
// This is called when the sky_browser website is connected to OpenSpace
|
||||
// Set all border colors to the border color in the master node
|
||||
if (global::windowDelegate->isMaster()) {
|
||||
@@ -189,7 +184,7 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void sendOutIdsToBrowsers() {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
// This is called when the sky_browser website is connected to OpenSpace
|
||||
// Send out identifiers to the browsers
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
@@ -207,13 +202,12 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void initializeBrowser(std::string identifier) {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
// Initialize browser with ID and its corresponding target
|
||||
LINFO("Initializing sky browser " + identifier);
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->setIsSyncedWithWwt(true);
|
||||
pair->initialize();
|
||||
}
|
||||
}
|
||||
@@ -234,6 +228,17 @@ namespace {
|
||||
module->addTargetBrowserPair(targetId, browserId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AAS WorldWide Telescope image collection url.
|
||||
*/
|
||||
[[codegen::luawrap]] ghoul::Dictionary getWwtImageCollectionUrl() {
|
||||
using namespace openspace;
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
ghoul::Dictionary url;
|
||||
url.setValue("url", module->wwtImageCollectionUrl());
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the loaded AAS WorldWide Telescope images that have been loaded.
|
||||
* Each image has a name, thumbnail url, equatorial spherical coordinates RA and Dec,
|
||||
@@ -242,17 +247,14 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] ghoul::Dictionary getListOfImages() {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
// Send image list to GUI
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
|
||||
std::string url = module->wwtImageCollectionUrl();
|
||||
// If no data has been loaded yet, download the data from the web!
|
||||
if (module->nLoadedImages() == 0) {
|
||||
std::string root = "https://raw.githubusercontent.com/WorldWideTelescope/"
|
||||
"wwt-web-client/master/assets/webclient-explore-root.wtml";
|
||||
|
||||
std::filesystem::path directory = absPath("${MODULE_SKYBROWSER}/wwtimagedata/");
|
||||
module->loadImages(root, directory);
|
||||
module->loadImages(url, directory);
|
||||
}
|
||||
|
||||
// Create Lua table to send to the GUI
|
||||
@@ -285,11 +287,11 @@ namespace {
|
||||
|
||||
/**
|
||||
* Returns a table of data regarding the current view and the sky browsers and targets.
|
||||
* \return Dictionary of data regarding the current targets
|
||||
* returns a table of data regarding the current targets.
|
||||
*/
|
||||
[[codegen::luawrap]] ghoul::Dictionary getTargetData() {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
ghoul::Dictionary data;
|
||||
|
||||
@@ -323,16 +325,6 @@ namespace {
|
||||
|
||||
for (const std::unique_ptr<TargetBrowserPair>& pair : pairs) {
|
||||
std::string id = pair->browserId();
|
||||
// Convert deque to vector so ghoul can read it
|
||||
std::vector<int> selectedImagesVector;
|
||||
const std::deque<int> selectedImages = pair->selectedImages();
|
||||
std::for_each(
|
||||
selectedImages.begin(),
|
||||
selectedImages.end(),
|
||||
[&](int i) {
|
||||
selectedImagesVector.push_back(i);
|
||||
}
|
||||
);
|
||||
|
||||
glm::dvec2 spherical = pair->targetDirectionEquatorial();
|
||||
glm::dvec3 cartesian = skybrowser::sphericalToCartesian(spherical);
|
||||
@@ -342,20 +334,19 @@ namespace {
|
||||
target.setValue("id", id);
|
||||
target.setValue("name", pair->browserGuiName());
|
||||
target.setValue("FOV", static_cast<double>(pair->verticalFov()));
|
||||
target.setValue("selectedImages", selectedImagesVector);
|
||||
target.setValue("selectedImages", pair->selectedImages());
|
||||
target.setValue("cartesianDirection", cartesian);
|
||||
target.setValue("ra", spherical.x);
|
||||
target.setValue("dec", spherical.y);
|
||||
target.setValue("roll", pair->targetRoll());
|
||||
target.setValue("color", pair->borderColor());
|
||||
target.setValue("size", glm::dvec2(pair->size()));
|
||||
std::vector<std::pair<std::string, glm::dvec3>> copies = pair->renderCopies();
|
||||
std::vector<std::pair<std::string, glm::dvec3>> copies = pair->displayCopies();
|
||||
ghoul::Dictionary copiesData;
|
||||
for (size_t i = 0; i < copies.size(); i++) {
|
||||
copiesData.setValue(copies[i].first, copies[i].second);
|
||||
}
|
||||
// Set table for the current target
|
||||
target.setValue("renderCopies", copiesData);
|
||||
target.setValue("displayCopies", copiesData);
|
||||
data.setValue(id, target);
|
||||
}
|
||||
}
|
||||
@@ -369,7 +360,7 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void adjustCamera(std::string id) {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
if (module->isCameraInSolarSystem()) {
|
||||
module->lookAtTarget(id);
|
||||
@@ -384,9 +375,9 @@ namespace {
|
||||
float opacity)
|
||||
{
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->setImageOpacity(imageIndex, opacity);
|
||||
}
|
||||
@@ -398,9 +389,9 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void centerTargetOnScreen(std::string identifier) {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->centerTargetOnScreen();
|
||||
}
|
||||
@@ -412,7 +403,7 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void setSelectedBrowser(std::string identifier) {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
global::moduleEngine->module<SkyBrowserModule>()->setSelectedBrowser(identifier);
|
||||
}
|
||||
|
||||
@@ -421,20 +412,20 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void createTargetBrowserPair() {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
|
||||
int noOfPairs = module->nPairs();
|
||||
std::string nameBrowser = "Sky Browser " + std::to_string(noOfPairs);
|
||||
std::string nameTarget = "Sky Target " + std::to_string(noOfPairs);
|
||||
std::string idBrowser = "SkyBrowser" + std::to_string(noOfPairs);
|
||||
std::string idTarget = "SkyTarget" + std::to_string(noOfPairs);
|
||||
int uniqueIdentifier = module->uniqueIdentifierCounter();
|
||||
std::string nameBrowser = "Sky Browser " + std::to_string(uniqueIdentifier);
|
||||
std::string nameTarget = "Sky Target " + std::to_string(uniqueIdentifier);
|
||||
std::string idBrowser = "SkyBrowser" + std::to_string(uniqueIdentifier);
|
||||
std::string idTarget = "SkyTarget" + std::to_string(uniqueIdentifier);
|
||||
// Determine starting point on screen for the target
|
||||
glm::vec3 positionBrowser = glm::vec3(-3.f, -3.f, -2.1f);
|
||||
glm::vec3 positionBrowser = glm::vec3(0.f, 0.f, -2.1f);
|
||||
glm::vec3 positionTarget = glm::vec3(0.9f, 0.4f, -2.1f);
|
||||
glm::dvec3 galacticTarget = skybrowser::localCameraToGalactic(positionTarget);
|
||||
std::string guiPath = "/Sky Browser";
|
||||
std::string url = "https://data.openspaceproject.com/dist/skybrowser/page/";
|
||||
std::string url = "http://wwt.openspaceproject.com/1/openspace/";
|
||||
double fov = 70.0;
|
||||
double size = skybrowser::sizeFromFov(fov, galacticTarget);
|
||||
|
||||
@@ -445,7 +436,7 @@ namespace {
|
||||
"Url = '" + url + "',"
|
||||
"FaceCamera = false,"
|
||||
"CartesianPosition = " + ghoul::to_string(positionBrowser) +
|
||||
"}";
|
||||
"}";
|
||||
|
||||
const std::string target = "{"
|
||||
"Identifier = '" + idTarget + "',"
|
||||
@@ -454,10 +445,10 @@ namespace {
|
||||
"Transform = {"
|
||||
"Translation = {"
|
||||
"Type = 'StaticTranslation',"
|
||||
"Position = {"
|
||||
+ std::to_string(galacticTarget.x) + ", "
|
||||
+ std::to_string(galacticTarget.y) + ", "
|
||||
+ std::to_string(galacticTarget.z) + ", "
|
||||
"Position = {" +
|
||||
std::to_string(galacticTarget.x) + ", " +
|
||||
std::to_string(galacticTarget.y) + ", " +
|
||||
std::to_string(galacticTarget.z) + ", " +
|
||||
"},"
|
||||
"},"
|
||||
"Rotation = {"
|
||||
@@ -475,7 +466,7 @@ namespace {
|
||||
"Opacity = 0.99"
|
||||
"},"
|
||||
"GUI = {"
|
||||
"Name = 'Sky Target', "
|
||||
"Name = '" + nameTarget + "', "
|
||||
"Path = '/SkyBrowser', "
|
||||
"}"
|
||||
"}";
|
||||
@@ -507,9 +498,9 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void removeTargetBrowserPair(std::string identifier) {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* found = module->getPair(identifier);
|
||||
TargetBrowserPair* found = module->pair(identifier);
|
||||
if (found) {
|
||||
std::string browser = found->browserId();
|
||||
std::string target = found->targetNodeId();
|
||||
@@ -540,7 +531,7 @@ namespace {
|
||||
float translationY)
|
||||
{
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
ScreenSpaceRenderable* renderable =
|
||||
global::renderEngine->screenSpaceRenderable(identifier);
|
||||
|
||||
@@ -559,11 +550,11 @@ namespace {
|
||||
int imageIndex)
|
||||
{
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
const ImageData& image = module->getWwtDataHandler()->getImage(imageIndex);
|
||||
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->removeSelectedImage(imageIndex);
|
||||
}
|
||||
@@ -578,9 +569,9 @@ namespace {
|
||||
double declination)
|
||||
{
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->setEquatorialAim(glm::dvec2(rightAscension, declination));
|
||||
}
|
||||
@@ -594,9 +585,9 @@ namespace {
|
||||
float verticalFieldOfView)
|
||||
{
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->setVerticalFov(verticalFieldOfView);
|
||||
}
|
||||
@@ -608,9 +599,9 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void scrollOverBrowser(std::string identifier, float scroll) {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->setVerticalFovWithScroll(scroll);
|
||||
}
|
||||
@@ -624,9 +615,9 @@ namespace {
|
||||
int blue)
|
||||
{
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->setBorderColor(glm::ivec3(red, green, blue));
|
||||
}
|
||||
@@ -636,46 +627,45 @@ namespace {
|
||||
* Sets the screen space size of the sky browser to the numbers specified by the input
|
||||
* [x, y].
|
||||
*/
|
||||
[[codegen::luawrap]] void setScreenSpaceSize(std::string identifier, float sizeX,
|
||||
float sizeY)
|
||||
[[codegen::luawrap]] void setBrowserRatio(std::string identifier, float ratio)
|
||||
{
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->setScreenSpaceSize(glm::vec2(sizeX, sizeY));
|
||||
pair->setBrowserRatio(ratio);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an identifier to a sky browser and adds a rendered copy to it.
|
||||
* \param raePosition Position in radius, azimuth, elevation coordinates
|
||||
* \param nCopies Number of copies
|
||||
* Takes an identifier to a sky browser and adds a rendered copy to it. The first argument
|
||||
* is the position of the first copy. The position is in RAE or Cartesian coordinates,
|
||||
* depending on if 'Use Radius Azimuth Elevation' is checked. The second argument is the
|
||||
* number of copies. If RAE is used, they will be evenly spread out on the azimuth.
|
||||
*/
|
||||
[[codegen::luawrap]] void addRenderCopy(std::string identifier,
|
||||
int numberOfCopies = 1,
|
||||
glm::vec3 radiusAzimuthElevationPosition = glm::vec3(2.1f, 0.f, 0.f))
|
||||
[[codegen::luawrap]] void addDisplayCopy(std::string identifier, int numberOfCopies = 1,
|
||||
glm::vec3 position = glm::vec3(2.1f, 0.f, 0.f))
|
||||
{
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->browser()->addRenderCopy(radiusAzimuthElevationPosition, numberOfCopies);
|
||||
pair->browser()->addDisplayCopy(position, numberOfCopies);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an identifier to a sky browser and removes the latest added rendered copy to it.
|
||||
*/
|
||||
[[codegen::luawrap]] void removeRenderCopy(std::string identifier) {
|
||||
[[codegen::luawrap]] void removeDisplayCopy(std::string identifier) {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->browser()->removeRenderCopy();
|
||||
pair->browser()->removeDisplayCopy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -684,16 +674,18 @@ namespace {
|
||||
*/
|
||||
[[codegen::luawrap]] void startFinetuningTarget(std::string identifier) {
|
||||
using namespace openspace;
|
||||
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
pair->startFinetuningTarget();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finetunes the target depending on a mouse drag. rendered copy to it.
|
||||
* Finetunes the target depending on a mouse drag. rendered copy to it. First argument
|
||||
* is the identifier of the sky browser, second is the start position of the drag
|
||||
* and third is the end position of the drag.
|
||||
*/
|
||||
[[codegen::luawrap]] void finetuneTargetPosition(std::string identifier,
|
||||
glm::vec2 startPosition,
|
||||
@@ -702,7 +694,7 @@ namespace {
|
||||
using namespace openspace;
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->getPair(identifier);
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
glm::vec2 startScreenSpace = skybrowser::pixelToScreenSpace2d(startPosition);
|
||||
glm::vec2 endScreenSpace = skybrowser::pixelToScreenSpace2d(endPosition);
|
||||
@@ -711,6 +703,70 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the image collection as loaded in the sky browser. Takes an identifier to the sky
|
||||
* browser.
|
||||
*/
|
||||
[[codegen::luawrap]] void loadingImageCollectionComplete(std::string identifier) {
|
||||
using namespace openspace;
|
||||
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
if (pair) {
|
||||
LINFO("Image collection is loaded in Screen Space Sky Browser " + identifier);
|
||||
pair->setImageCollectionIsLoaded(true);
|
||||
// Add all selected images to WorldWide Telescope
|
||||
const std::vector<int>& images = pair->selectedImages();
|
||||
std::for_each(
|
||||
images.rbegin(), images.rend(),
|
||||
[&](int index) {
|
||||
const ImageData& image = module->getWwtDataHandler()->getImage(index);
|
||||
// Index of image is used as layer ID as it is unique in the image data set
|
||||
pair->browser()->addImageLayerToWwt(image.imageUrl, index);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or hide all targets and browsers. Takes a boolean that sets it to either be shown
|
||||
* or not.
|
||||
*/
|
||||
[[codegen::luawrap]] void showAllTargetsAndBrowsers(bool show) {
|
||||
using namespace openspace;
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
const std::vector<std::unique_ptr<TargetBrowserPair>>& pairs = module->getPairs();
|
||||
for (const std::unique_ptr<TargetBrowserPair>& pair : pairs) {
|
||||
pair->setEnabled(show);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Point spacecraft to the equatorial coordinates the target points to. Takes an
|
||||
* identifier to a sky browser.
|
||||
*/
|
||||
[[codegen::luawrap]] void pointSpaceCraft(std::string identifier) {
|
||||
using namespace openspace;
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
glm::dvec2 equatorial = pair->targetDirectionEquatorial();
|
||||
global::eventEngine->publishEvent<events::EventPointSpacecraft>(
|
||||
equatorial.x,
|
||||
equatorial.y,
|
||||
module->spaceCraftAnimationTime()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop animations. Takes an identifier to a sky browser.
|
||||
*/
|
||||
[[codegen::luawrap]] void stopAnimations(std::string identifier) {
|
||||
using namespace openspace;
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
TargetBrowserPair* pair = module->pair(identifier);
|
||||
pair->stopAnimations();
|
||||
}
|
||||
|
||||
#include "skybrowsermodule_lua_codegen.cpp"
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -92,7 +92,7 @@ Browser::Browser(const ghoul::Dictionary& dictionary)
|
||||
if (dictionary.hasValue<std::string>(UrlInfo.identifier)) {
|
||||
_url = dictionary.value<std::string>(UrlInfo.identifier);
|
||||
}
|
||||
|
||||
|
||||
// Handle target dimension property
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
_url = p.url.value_or(_url);
|
||||
|
||||
@@ -63,21 +63,6 @@ namespace {
|
||||
"be rendered in the target."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo AnimationSpeedInfo = {
|
||||
"AnimationSpeed",
|
||||
"Animation Speed",
|
||||
"The factor which is multiplied with the animation speed of the target."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo AnimationThresholdInfo =
|
||||
{
|
||||
"AnimationThreshold",
|
||||
"Animation Threshold",
|
||||
"The threshold for when the target is determined to have appeared at its "
|
||||
"destination. Angle in radians between the destination and the target position "
|
||||
"in equatorial Cartesian coordinate system."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo LineWidthInfo = {
|
||||
"LineWidth",
|
||||
"Line Width",
|
||||
@@ -91,12 +76,6 @@ namespace {
|
||||
// [[codegen::verbatim(RectangleThresholdInfo.description)]]
|
||||
std::optional<float> rectangleThreshold;
|
||||
|
||||
// [[codegen::verbatim(AnimationSpeedInfo.description)]]
|
||||
std::optional<double> animationSpeed;
|
||||
|
||||
// [[codegen::verbatim(AnimationThresholdInfo.description)]]
|
||||
std::optional<float> animationThreshold;
|
||||
|
||||
// [[codegen::verbatim(LineWidthInfo.description)]]
|
||||
std::optional<float> lineWidth;
|
||||
};
|
||||
@@ -106,29 +85,25 @@ namespace {
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation RenderableSkyTarget::Documentation() {
|
||||
return codegen::doc<Parameters>("skybrowser_renderableskytarget");
|
||||
}
|
||||
|
||||
RenderableSkyTarget::RenderableSkyTarget(const ghoul::Dictionary& dictionary)
|
||||
: RenderablePlane(dictionary)
|
||||
, _crossHairSize(crossHairSizeInfo, 2.f, 1.f, 10.f)
|
||||
, _showRectangleThreshold(RectangleThresholdInfo, 5.f, 0.1f, 70.f)
|
||||
, _stopAnimationThreshold(AnimationThresholdInfo, 5.0f, 1.f, 10.f)
|
||||
, _animationSpeed(AnimationSpeedInfo, 5.0, 0.1, 10.0)
|
||||
, _lineWidth(LineWidthInfo, 13.f, 1.f, 100.f)
|
||||
, _borderColor(220, 220, 220)
|
||||
{
|
||||
// Handle target dimension property
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
|
||||
_crossHairSize = p.crossHairSize.value_or(_crossHairSize);
|
||||
addProperty(_crossHairSize);
|
||||
|
||||
|
||||
_showRectangleThreshold = p.rectangleThreshold.value_or(_showRectangleThreshold);
|
||||
addProperty(_showRectangleThreshold);
|
||||
|
||||
_stopAnimationThreshold = p.crossHairSize.value_or(_stopAnimationThreshold);
|
||||
addProperty(_stopAnimationThreshold);
|
||||
|
||||
_animationSpeed = p.animationSpeed.value_or(_animationSpeed);
|
||||
addProperty(_animationSpeed);
|
||||
|
||||
addProperty(_lineWidth);
|
||||
}
|
||||
@@ -166,15 +141,15 @@ void RenderableSkyTarget::render(const RenderData& data, RendererTasks&) {
|
||||
ZoneScoped
|
||||
const bool showRectangle = _verticalFov > _showRectangleThreshold;
|
||||
|
||||
glm::vec4 color = { glm::vec3(_borderColor) / 255.f, _opacity.value() };
|
||||
glm::vec4 color = { glm::vec3(_borderColor) / 255.f, 1.0 };
|
||||
|
||||
_shader->activate();
|
||||
_shader->setUniform("opacity", _opacity);
|
||||
_shader->setUniform("opacity", opacity());
|
||||
|
||||
_shader->setUniform("crossHairSize", _crossHairSize);
|
||||
_shader->setUniform("showRectangle", showRectangle);
|
||||
_shader->setUniform("lineWidth", _lineWidth * 0.0001f);
|
||||
_shader->setUniform("dimensions", _dimensions);
|
||||
_shader->setUniform("ratio", _ratio);
|
||||
_shader->setUniform("lineColor", color);
|
||||
_shader->setUniform("fov", static_cast<float>(_verticalFov));
|
||||
|
||||
@@ -239,10 +214,10 @@ void RenderableSkyTarget::render(const RenderData& data, RendererTasks&) {
|
||||
_shader->deactivate();
|
||||
}
|
||||
|
||||
void RenderableSkyTarget::setDimensions(glm::vec2 dimensions) {
|
||||
void RenderableSkyTarget::setRatio(float ratio) {
|
||||
// To avoid flooring of the size of the target, multiply by factor of 100
|
||||
// Object size is really the pixel size so this calculation is not exact
|
||||
_dimensions = glm::ivec2(dimensions * 100.f);
|
||||
_ratio = ratio;
|
||||
}
|
||||
|
||||
void RenderableSkyTarget::highlight(const glm::ivec3& addition) {
|
||||
@@ -253,22 +228,6 @@ void RenderableSkyTarget::removeHighlight(const glm::ivec3& removal) {
|
||||
_borderColor -= removal;
|
||||
}
|
||||
|
||||
float RenderableSkyTarget::opacity() const {
|
||||
return _opacity;
|
||||
}
|
||||
|
||||
double RenderableSkyTarget::animationSpeed() const {
|
||||
return _animationSpeed;
|
||||
}
|
||||
|
||||
double RenderableSkyTarget::stopAnimationThreshold() const {
|
||||
return _stopAnimationThreshold * 0.0001;
|
||||
}
|
||||
|
||||
void RenderableSkyTarget::setOpacity(float opacity) {
|
||||
_opacity = opacity;
|
||||
}
|
||||
|
||||
void RenderableSkyTarget::setVerticalFov(double fov) {
|
||||
_verticalFov = fov;
|
||||
}
|
||||
|
||||
@@ -48,32 +48,38 @@ namespace {
|
||||
"frame rate."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo RenderCopyInfo = {
|
||||
"RenderCopy",
|
||||
"RAE Position Of A Copy Of The Sky Browser",
|
||||
"Render a copy of this sky browser at an additional position. This copy will not "
|
||||
"be interactive. The position is in RAE (Radius, Azimuth, Elevation) coordinates."
|
||||
constexpr const openspace::properties::Property::PropertyInfo DisplayCopyInfo = {
|
||||
"DisplayCopy",
|
||||
"Display Copy Position",
|
||||
"Display a copy of this sky browser at an additional position. This copy will not "
|
||||
"be interactive. The position is in RAE (Radius, Azimuth, Elevation) coordinates "
|
||||
"or Cartesian, depending on if the browser uses RAE or Cartesian coordinates."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo RenderOnMasterInfo = {
|
||||
"RenderOnlyOnMaster",
|
||||
"Render Only On Master",
|
||||
"Render the interactive sky browser only on the master node (this setting won't "
|
||||
"affect the copies). This setting allows mouse interactions in a dome "
|
||||
"environment."
|
||||
constexpr const openspace::properties::Property::PropertyInfo DisplayCopyShowInfo = {
|
||||
"ShowDisplayCopy",
|
||||
"Show Display Copy",
|
||||
"Show the display copy."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo IsHiddenInfo = {
|
||||
"IsHidden",
|
||||
"Is Hidden",
|
||||
"If checked, the browser will be not be displayed. If it is not checked, it will "
|
||||
"be."
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(ScreenSpaceSkyBrowser)]] Parameters {
|
||||
// [[codegen::verbatim(TextureQualityInfo.description)]]
|
||||
std::optional<float> textureQuality;
|
||||
|
||||
// [[codegen::verbatim(RenderOnMasterInfo.description)]]
|
||||
std::optional<bool> renderOnlyOnMaster;
|
||||
// [[codegen::verbatim(IsHiddenInfo.description)]]
|
||||
std::optional<bool> isHidden;
|
||||
};
|
||||
|
||||
#include "screenspaceskybrowser_codegen.cpp"
|
||||
|
||||
glm::ivec3 randomBorderColor(glm::ivec3 highlight) {
|
||||
glm::ivec3 randomBorderColor() {
|
||||
// Generate a random border color with sufficient lightness and a n
|
||||
std::random_device rd;
|
||||
// Hue is in the unit degrees [0, 360]
|
||||
@@ -82,13 +88,8 @@ namespace {
|
||||
// Value in saturation are in the unit percent [0,1]
|
||||
float value = 0.9f; // Brightness
|
||||
float saturation = 0.5f;
|
||||
glm::ivec3 rgbColor;
|
||||
glm::ivec3 highlighted;
|
||||
do {
|
||||
glm::vec3 hsvColor = glm::vec3(hue(rd), saturation, value);
|
||||
rgbColor = glm::ivec3(glm::rgbColor(hsvColor) * 255.f);
|
||||
highlighted = rgbColor + highlight;
|
||||
} while (highlighted.x < 255 && highlighted.y < 255 && highlighted.z < 255);
|
||||
glm::vec3 hsvColor = glm::vec3(hue(rd), saturation, value);
|
||||
glm::ivec3 rgbColor = glm::ivec3(glm::rgbColor(hsvColor) * 255.f);
|
||||
|
||||
return rgbColor;
|
||||
}
|
||||
@@ -96,41 +97,60 @@ namespace {
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation ScreenSpaceSkyBrowser::Documentation() {
|
||||
return codegen::doc<Parameters>("skybrowser_screenspaceskybrowser");
|
||||
}
|
||||
|
||||
ScreenSpaceSkyBrowser::ScreenSpaceSkyBrowser(const ghoul::Dictionary& dictionary)
|
||||
: ScreenSpaceRenderable(dictionary)
|
||||
, WwtCommunicator(dictionary)
|
||||
, _textureQuality(TextureQualityInfo, 0.5f, 0.25f, 1.f)
|
||||
, _renderOnlyOnMaster(RenderOnMasterInfo, false)
|
||||
, _isHidden(IsHiddenInfo, true)
|
||||
{
|
||||
_identifier = makeUniqueIdentifier(_identifier);
|
||||
|
||||
// Handle target dimension property
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
_textureQuality = p.textureQuality.value_or(_textureQuality);
|
||||
_renderOnlyOnMaster = p.renderOnlyOnMaster.value_or(_renderOnlyOnMaster);
|
||||
_isHidden = p.isHidden.value_or(_isHidden);
|
||||
|
||||
addProperty(_isHidden);
|
||||
addProperty(_url);
|
||||
addProperty(_browserPixeldimensions);
|
||||
addProperty(_reload);
|
||||
addProperty(_textureQuality);
|
||||
addProperty(_renderOnlyOnMaster);
|
||||
|
||||
_textureQuality.onChange([this]() { _textureDimensionsIsDirty = true; });
|
||||
|
||||
// Ensure that the browser is placed at the z-coordinate of the screen space plane
|
||||
glm::vec2 screenPosition = _cartesianPosition.value();
|
||||
_cartesianPosition = glm::vec3(screenPosition, skybrowser::ScreenSpaceZ);
|
||||
|
||||
if (global::windowDelegate->isMaster()) {
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
_borderColor = randomBorderColor(module->highlight());
|
||||
_borderColor = randomBorderColor();
|
||||
}
|
||||
_scale = _size.y * 0.5f;
|
||||
|
||||
_scale.onChange([this]() {
|
||||
updateTextureResolution();
|
||||
});
|
||||
|
||||
_useRadiusAzimuthElevation.onChange(
|
||||
[this]() {
|
||||
std::for_each(
|
||||
_displayCopies.begin(),
|
||||
_displayCopies.end(),
|
||||
[this](std::unique_ptr<properties::Vec3Property>& copy) {
|
||||
if (_useRadiusAzimuthElevation) {
|
||||
*copy = sphericalToRae(cartesianToSpherical(copy->value()));
|
||||
|
||||
}
|
||||
else {
|
||||
*copy = sphericalToCartesian(raeToSpherical(copy->value()));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ScreenSpaceSkyBrowser::~ScreenSpaceSkyBrowser() {
|
||||
SkyBrowserModule* module = global::moduleEngine->module<SkyBrowserModule>();
|
||||
if (module && module->getPair(identifier())) {
|
||||
if (module && module->pair(identifier())) {
|
||||
module->removeTargetBrowserPair(identifier());
|
||||
}
|
||||
}
|
||||
@@ -157,10 +177,18 @@ glm::dvec2 ScreenSpaceSkyBrowser::fineTuneVector(const glm::dvec2& drag) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ScreenSpaceSkyBrowser::isInitialized() const {
|
||||
return _isInitialized;
|
||||
}
|
||||
|
||||
void ScreenSpaceSkyBrowser::setIdInBrowser() const {
|
||||
WwtCommunicator::setIdInBrowser(identifier());
|
||||
}
|
||||
|
||||
void ScreenSpaceSkyBrowser::setIsInitialized(bool isInitialized) {
|
||||
_isInitialized = isInitialized;
|
||||
}
|
||||
|
||||
void ScreenSpaceSkyBrowser::updateTextureResolution() {
|
||||
// Scale texture depending on the height of the window
|
||||
// Set texture size to the actual pixel size it covers
|
||||
@@ -168,8 +196,7 @@ void ScreenSpaceSkyBrowser::updateTextureResolution() {
|
||||
|
||||
// If the scale is 1, it covers half the window. Hence multiplication with 2
|
||||
float newResY = pixels.y * 2.f * _scale;
|
||||
float ratio = _size.x / _size.y;
|
||||
float newResX = newResY * ratio;
|
||||
float newResX = newResY * _ratio;
|
||||
glm::vec2 newSize = glm::vec2(newResX , newResY) * _textureQuality.value();
|
||||
|
||||
_browserPixeldimensions = glm::ivec2(newSize);
|
||||
@@ -177,55 +204,63 @@ void ScreenSpaceSkyBrowser::updateTextureResolution() {
|
||||
_objectSize = glm::ivec3(_texture->dimensions());
|
||||
}
|
||||
|
||||
void ScreenSpaceSkyBrowser::addRenderCopy(const glm::vec3& raePosition, int nCopies) {
|
||||
size_t start = _renderCopies.size();
|
||||
void ScreenSpaceSkyBrowser::addDisplayCopy(const glm::vec3& raePosition, int nCopies) {
|
||||
size_t start = _displayCopies.size();
|
||||
for (int i = 0; i < nCopies; i++) {
|
||||
openspace::properties::Property::PropertyInfo info = RenderCopyInfo;
|
||||
openspace::properties::Property::PropertyInfo info = DisplayCopyInfo;
|
||||
float azimuth = i * glm::two_pi<float>() / nCopies;
|
||||
glm::vec3 position = raePosition + glm::vec3(0.f, azimuth, 0.f);
|
||||
std::string id = "RenderCopy" + std::to_string(start + i);
|
||||
info.identifier = id.c_str();
|
||||
_renderCopies.push_back(
|
||||
std::string idDisplayCopy = "DisplayCopy" + std::to_string(start + i);
|
||||
info.identifier = idDisplayCopy.c_str();
|
||||
_displayCopies.push_back(
|
||||
std::make_unique<properties::Vec3Property>(
|
||||
info,
|
||||
position,
|
||||
glm::vec3(0.f, -glm::pi<float>(), -glm::half_pi<float>()),
|
||||
glm::vec3(10.f, glm::pi<float>(), glm::half_pi<float>())
|
||||
glm::vec3(-4.f, -4.f, -10.f),
|
||||
glm::vec3(4.f, 4.f, glm::half_pi<float>())
|
||||
)
|
||||
);
|
||||
addProperty(_renderCopies.back().get());
|
||||
openspace::properties::Property::PropertyInfo showInfo = DisplayCopyShowInfo;
|
||||
std::string idDisplayCopyVisible = "ShowDisplayCopy" + std::to_string(start + i);
|
||||
showInfo.identifier = idDisplayCopyVisible.c_str();
|
||||
_showDisplayCopies.push_back(
|
||||
std::make_unique<properties::BoolProperty>(
|
||||
showInfo,
|
||||
true
|
||||
)
|
||||
);
|
||||
addProperty(_displayCopies.back().get());
|
||||
addProperty(_showDisplayCopies.back().get());
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenSpaceSkyBrowser::removeRenderCopy() {
|
||||
if (!_renderCopies.empty()) {
|
||||
removeProperty(_renderCopies.back().get());
|
||||
_renderCopies.pop_back();
|
||||
void ScreenSpaceSkyBrowser::removeDisplayCopy() {
|
||||
if (!_displayCopies.empty()) {
|
||||
removeProperty(_displayCopies.back().get());
|
||||
_displayCopies.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, glm::dvec3>>
|
||||
ScreenSpaceSkyBrowser::renderCopies() const
|
||||
ScreenSpaceSkyBrowser::displayCopies() const
|
||||
{
|
||||
std::vector<std::pair<std::string, glm::dvec3>> vec;
|
||||
std::for_each(
|
||||
_renderCopies.begin(),
|
||||
_renderCopies.end(),
|
||||
[&](const std::unique_ptr<properties::Vec3Property>& copy) {
|
||||
std::pair<std::string, glm::dvec3> pair = {
|
||||
copy.get()->identifier(),
|
||||
glm::dvec3(copy.get()->value())
|
||||
};
|
||||
vec.push_back(pair);
|
||||
}
|
||||
);
|
||||
using vec3Property = std::unique_ptr<properties::Vec3Property>;
|
||||
for (const vec3Property& copy : _displayCopies) {
|
||||
vec.push_back({ copy->identifier(), copy->value() });
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
void ScreenSpaceSkyBrowser::moveRenderCopy(int i, glm::vec3 raePosition) {
|
||||
if (i < static_cast<int>(_renderCopies.size()) && i >= 0) {
|
||||
*_renderCopies[i].get() = raePosition;
|
||||
std::vector<std::pair<std::string, bool>>
|
||||
ScreenSpaceSkyBrowser::showDisplayCopies() const
|
||||
{
|
||||
std::vector<std::pair<std::string, bool>> vec;
|
||||
using boolProperty = std::unique_ptr<properties::BoolProperty>;
|
||||
for (const boolProperty& copy : _showDisplayCopies) {
|
||||
vec.push_back({copy->identifier(), copy->value()});
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
bool ScreenSpaceSkyBrowser::deinitializeGL() {
|
||||
@@ -237,12 +272,7 @@ bool ScreenSpaceSkyBrowser::deinitializeGL() {
|
||||
void ScreenSpaceSkyBrowser::render() {
|
||||
WwtCommunicator::render();
|
||||
|
||||
// If the sky browser only should be rendered on master, don't use the
|
||||
// global rotation
|
||||
if (_renderOnlyOnMaster && global::windowDelegate->isMaster()) {
|
||||
draw(translationMatrix() * localRotationMatrix() * scaleMatrix());
|
||||
}
|
||||
else if (!_renderOnlyOnMaster) {
|
||||
if (!_isHidden) {
|
||||
draw(
|
||||
globalRotationMatrix() *
|
||||
translationMatrix() *
|
||||
@@ -251,20 +281,29 @@ void ScreenSpaceSkyBrowser::render() {
|
||||
);
|
||||
}
|
||||
|
||||
// Render a copy that is not interactive
|
||||
for (const std::unique_ptr<properties::Vec3Property>& copy : _renderCopies) {
|
||||
glm::vec3 spherical = sphericalToCartesian(raeToSpherical(copy.get()->value()));
|
||||
glm::mat4 localRotation = glm::inverse(glm::lookAt(
|
||||
glm::vec3(0.f),
|
||||
glm::normalize(spherical),
|
||||
glm::vec3(0.f, 1.f, 0.f)
|
||||
));
|
||||
draw(
|
||||
globalRotationMatrix() *
|
||||
glm::translate(glm::mat4(1.f), spherical) *
|
||||
localRotation *
|
||||
scaleMatrix()
|
||||
);
|
||||
// Render the display copies
|
||||
for (size_t i = 0; i < _displayCopies.size(); i++) {
|
||||
if (_showDisplayCopies[i]->value()) {
|
||||
glm::vec3 coordinates = _displayCopies[i]->value();
|
||||
if (_useRadiusAzimuthElevation) {
|
||||
coordinates = sphericalToCartesian(raeToSpherical(coordinates));
|
||||
}
|
||||
glm::mat4 localRotation = glm::mat4(1.f);
|
||||
if (_faceCamera) {
|
||||
localRotation = glm::inverse(glm::lookAt(
|
||||
glm::vec3(0.f),
|
||||
glm::normalize(coordinates),
|
||||
glm::vec3(0.f, 1.f, 0.f)
|
||||
));
|
||||
}
|
||||
|
||||
draw(
|
||||
globalRotationMatrix() *
|
||||
glm::translate(glm::mat4(1.f), coordinates) *
|
||||
localRotation *
|
||||
scaleMatrix()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,9 +315,12 @@ void ScreenSpaceSkyBrowser::update() {
|
||||
updateTextureResolution();
|
||||
_textureDimensionsIsDirty = false;
|
||||
}
|
||||
if (_sizeIsDirty) {
|
||||
updateScreenSpaceSize();
|
||||
_sizeIsDirty = false;
|
||||
if (_ratioIsDirty) {
|
||||
updateTextureResolution();
|
||||
_ratioIsDirty = false;
|
||||
}
|
||||
if (_shouldReload) {
|
||||
_isInitialized = false;
|
||||
}
|
||||
|
||||
WwtCommunicator::update();
|
||||
@@ -289,7 +331,7 @@ void ScreenSpaceSkyBrowser::setVerticalFovWithScroll(float scroll) {
|
||||
// Make scroll more sensitive the smaller the FOV
|
||||
double x = _verticalFov;
|
||||
double zoomFactor = atan(x / 50.0) + exp(x / 40.0) - 0.99999999999999999999999999999;
|
||||
double zoom = scroll > 0.0 ? -zoomFactor : zoomFactor;
|
||||
double zoom = scroll > 0.0 ? zoomFactor : -zoomFactor;
|
||||
_verticalFov = std::clamp(_verticalFov + zoom, 0.0, 70.0);
|
||||
}
|
||||
|
||||
@@ -313,22 +355,13 @@ void ScreenSpaceSkyBrowser::setOpacity(float opacity) {
|
||||
_opacity = opacity;
|
||||
}
|
||||
|
||||
void ScreenSpaceSkyBrowser::setScreenSpaceSize(glm::vec2 newSize) {
|
||||
_size = std::move(newSize);
|
||||
_sizeIsDirty = true;
|
||||
}
|
||||
|
||||
void ScreenSpaceSkyBrowser::updateScreenSpaceSize() {
|
||||
_scale = abs(_size.y) * 0.5f;
|
||||
updateTextureResolution();
|
||||
void ScreenSpaceSkyBrowser::setRatio(float ratio) {
|
||||
_ratio = ratio;
|
||||
_ratioIsDirty = true;
|
||||
}
|
||||
|
||||
float ScreenSpaceSkyBrowser::opacity() const {
|
||||
return _opacity;
|
||||
}
|
||||
|
||||
glm::vec2 ScreenSpaceSkyBrowser::size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -63,16 +63,6 @@ void TargetBrowserPair::setImageOrder(int i, int order) {
|
||||
_browser->setImageOrder(i, order);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::removeHighlight(const glm::ivec3& color) {
|
||||
_targetRenderable->removeHighlight(color);
|
||||
_browser->removeHighlight(color);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::highlight(const glm::ivec3& color) {
|
||||
_browser->highlight(color);
|
||||
_targetRenderable->highlight(color);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::aimTargetGalactic(glm::dvec3 direction) {
|
||||
std::string id = _targetNode->identifier();
|
||||
glm::dvec3 positionCelestial = glm::normalize(direction) *
|
||||
@@ -114,7 +104,7 @@ void TargetBrowserPair::fineTuneTarget(const glm::vec2& startMouse,
|
||||
}
|
||||
|
||||
void TargetBrowserPair::synchronizeAim() {
|
||||
if (!_moveTarget.isAnimating()) {
|
||||
if (!_targetAnimation.isAnimating() && _browser->isInitialized()) {
|
||||
_browser->setEquatorialAim(targetDirectionEquatorial());
|
||||
_browser->setTargetRoll(targetRoll());
|
||||
_targetRenderable->setVerticalFov(_browser->verticalFov());
|
||||
@@ -123,7 +113,7 @@ void TargetBrowserPair::synchronizeAim() {
|
||||
|
||||
void TargetBrowserPair::setEnabled(bool enable) {
|
||||
_browser->setEnabled(enable);
|
||||
_targetRenderable->property("Enabled")->set(false);
|
||||
_targetRenderable->property("Enabled")->set(enable);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::setOpacity(float opacity) {
|
||||
@@ -137,8 +127,11 @@ bool TargetBrowserPair::isEnabled() const {
|
||||
|
||||
void TargetBrowserPair::initialize() {
|
||||
_targetRenderable->setColor(_browser->borderColor());
|
||||
_targetRenderable->setDimensions(_browser->screenSpaceDimensions());
|
||||
glm::vec2 dim = _browser->screenSpaceDimensions();
|
||||
_targetRenderable->setRatio(dim.x / dim.y);
|
||||
_browser->updateBorderColor();
|
||||
_browser->hideChromeInterface();
|
||||
_browser->setIsInitialized(true);
|
||||
}
|
||||
|
||||
glm::ivec3 TargetBrowserPair::borderColor() const {
|
||||
@@ -172,31 +165,70 @@ std::string TargetBrowserPair::targetNodeId() const {
|
||||
return _targetNode->identifier();
|
||||
}
|
||||
|
||||
glm::vec2 TargetBrowserPair::size() const {
|
||||
return _browser->size();
|
||||
float TargetBrowserPair::browserRatio() const {
|
||||
return _browser->browserRatio();
|
||||
}
|
||||
|
||||
double TargetBrowserPair::verticalFov() const {
|
||||
return _browser->verticalFov();
|
||||
}
|
||||
|
||||
const std::deque<int>& TargetBrowserPair::selectedImages() const {
|
||||
return _browser->getSelectedImages();
|
||||
std::vector<int> TargetBrowserPair::selectedImages() const {
|
||||
return _browser->selectedImages();
|
||||
}
|
||||
|
||||
ghoul::Dictionary TargetBrowserPair::dataAsDictionary() const {
|
||||
glm::dvec2 spherical = targetDirectionEquatorial();
|
||||
glm::dvec3 cartesian = skybrowser::sphericalToCartesian(spherical);
|
||||
|
||||
ghoul::Dictionary res;
|
||||
res.setValue("id", browserId());
|
||||
res.setValue("name", browserGuiName());
|
||||
res.setValue("fov", static_cast<double>(verticalFov()));
|
||||
res.setValue("ra", spherical.x);
|
||||
res.setValue("dec", spherical.y);
|
||||
res.setValue("roll", targetRoll());
|
||||
res.setValue("color", borderColor());
|
||||
res.setValue("cartesianDirection", cartesian);
|
||||
res.setValue("ratio", static_cast<double>(browserRatio()));
|
||||
res.setValue("isFacingCamera", isFacingCamera());
|
||||
res.setValue("isUsingRae", isUsingRadiusAzimuthElevation());
|
||||
res.setValue("selectedImages", selectedImages());
|
||||
res.setValue("scale", static_cast<double>(_browser->scale()));
|
||||
res.setValue("opacities", _browser->opacities());
|
||||
|
||||
std::vector<std::pair<std::string, glm::dvec3>> copies = displayCopies();
|
||||
std::vector<std::pair<std::string, bool>> showCopies = _browser->showDisplayCopies();
|
||||
ghoul::Dictionary copiesData;
|
||||
for (size_t i = 0; i < copies.size(); i++) {
|
||||
ghoul::Dictionary copy;
|
||||
copy.setValue("position", copies[i].second);
|
||||
copy.setValue("show", showCopies[i].second);
|
||||
copy.setValue("idShowProperty", showCopies[i].first);
|
||||
copiesData.setValue(copies[i].first, copy);
|
||||
}
|
||||
// Set table for the current target
|
||||
res.setValue("displayCopies", copiesData);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void TargetBrowserPair::selectImage(const ImageData& image, int i) {
|
||||
// Load image into browser
|
||||
_browser->displayImage(image.imageUrl, i);
|
||||
_browser->selectImage(image.imageUrl, i);
|
||||
|
||||
// If the image has coordinates, move the target
|
||||
if (image.hasCelestialCoords) {
|
||||
// Animate the target to the image coordinate position
|
||||
// unlock();
|
||||
glm::dvec3 galactic = skybrowser::equatorialToGalactic(image.equatorialCartesian);
|
||||
startAnimation(galactic * skybrowser::CelestialSphereRadius, image.fov);
|
||||
}
|
||||
}
|
||||
|
||||
void TargetBrowserPair::addImageLayerToWwt(const std::string& url, int i) {
|
||||
_browser->addImageLayerToWwt(url, i);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::removeSelectedImage(int i) {
|
||||
_browser->removeSelectedImage(i);
|
||||
}
|
||||
@@ -209,8 +241,8 @@ void TargetBrowserPair::setImageOpacity(int i, float opacity) {
|
||||
_browser->setImageOpacity(i, opacity);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::hideChromeInterface(bool shouldHide) {
|
||||
_browser->hideChromeInterface(shouldHide);
|
||||
void TargetBrowserPair::hideChromeInterface() {
|
||||
_browser->hideChromeInterface();
|
||||
}
|
||||
|
||||
void TargetBrowserPair::sendIdToBrowser() const {
|
||||
@@ -221,12 +253,12 @@ void TargetBrowserPair::updateBrowserSize() {
|
||||
_browser->updateBrowserSize();
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, glm::dvec3>> TargetBrowserPair::renderCopies() const {
|
||||
return _browser->renderCopies();
|
||||
std::vector<std::pair<std::string, glm::dvec3>> TargetBrowserPair::displayCopies() const {
|
||||
return _browser->displayCopies();
|
||||
}
|
||||
|
||||
void TargetBrowserPair::setIsSyncedWithWwt(bool isSynced) {
|
||||
_browser->setIsSyncedWithWwt(isSynced);
|
||||
bool TargetBrowserPair::isImageCollectionLoaded() {
|
||||
return _browser->isImageCollectionLoaded();
|
||||
}
|
||||
|
||||
void TargetBrowserPair::setVerticalFov(double vfov) {
|
||||
@@ -235,7 +267,6 @@ void TargetBrowserPair::setVerticalFov(double vfov) {
|
||||
}
|
||||
|
||||
void TargetBrowserPair::setEquatorialAim(const glm::dvec2& aim) {
|
||||
_equatorialAim = aim;
|
||||
aimTargetGalactic(
|
||||
skybrowser::equatorialToGalactic(skybrowser::sphericalToCartesian(aim))
|
||||
);
|
||||
@@ -243,28 +274,31 @@ void TargetBrowserPair::setEquatorialAim(const glm::dvec2& aim) {
|
||||
}
|
||||
|
||||
void TargetBrowserPair::setBorderColor(const glm::ivec3& color) {
|
||||
_borderColor = color;
|
||||
_targetRenderable->setColor(color);
|
||||
_browser->setBorderColor(color);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::setScreenSpaceSize(const glm::vec2& dimensions) {
|
||||
_browser->setScreenSpaceSize(dimensions);
|
||||
_targetRenderable->setDimensions(dimensions);
|
||||
void TargetBrowserPair::setBrowserRatio(float ratio) {
|
||||
_browser->setRatio(ratio);
|
||||
_targetRenderable->setRatio(ratio);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::setVerticalFovWithScroll(float scroll) {
|
||||
_browser->setVerticalFovWithScroll(scroll);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::setImageCollectionIsLoaded(bool isLoaded) {
|
||||
_browser->setImageCollectionIsLoaded(isLoaded);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::incrementallyAnimateToCoordinate() {
|
||||
// Animate the target before the field of view starts to animate
|
||||
if (_moveTarget.isAnimating()) {
|
||||
aimTargetGalactic(_moveTarget.getNewValue());
|
||||
if (_targetAnimation.isAnimating()) {
|
||||
aimTargetGalactic(_targetAnimation.getNewValue());
|
||||
}
|
||||
else if (!_moveTarget.isAnimating() && _targetIsAnimating) {
|
||||
else if (!_targetAnimation.isAnimating() && _targetIsAnimating) {
|
||||
// Set the finished position
|
||||
aimTargetGalactic(_moveTarget.getNewValue());
|
||||
aimTargetGalactic(_targetAnimation.getNewValue());
|
||||
_fovAnimation.start();
|
||||
_targetIsAnimating = false;
|
||||
}
|
||||
@@ -275,10 +309,21 @@ void TargetBrowserPair::incrementallyAnimateToCoordinate() {
|
||||
}
|
||||
|
||||
void TargetBrowserPair::startFading(float goal, float fadeTime) {
|
||||
_fadeTarget = skybrowser::Animation(_targetRenderable->opacity(), goal, fadeTime);
|
||||
_fadeBrowser = skybrowser::Animation(_browser->opacity(), goal, fadeTime);
|
||||
_fadeTarget.start();
|
||||
_fadeBrowser.start();
|
||||
const std::string script = fmt::format(
|
||||
"openspace.setPropertyValueSingle('Scene.{0}.Renderable.Fade', {2}, {3});"
|
||||
"openspace.setPropertyValueSingle('ScreenSpace.{1}.Fade', {2}, {3});",
|
||||
_targetNode->identifier(), _browser->identifier(), goal, fadeTime
|
||||
);
|
||||
|
||||
global::scriptEngine->queueScript(
|
||||
script,
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
|
||||
void TargetBrowserPair::stopAnimations() {
|
||||
_fovAnimation.stop();
|
||||
_targetAnimation.stop();
|
||||
}
|
||||
|
||||
void TargetBrowserPair::startAnimation(glm::dvec3 galacticCoords, double fovEnd) {
|
||||
@@ -294,8 +339,8 @@ void TargetBrowserPair::startAnimation(glm::dvec3 galacticCoords, double fovEnd)
|
||||
skybrowser::CelestialSphereRadius;
|
||||
double targetSpeed = module->targetAnimationSpeed();
|
||||
double angle = skybrowser::angleBetweenVectors(start, galacticCoords);
|
||||
_moveTarget = skybrowser::Animation(start, galacticCoords, angle / targetSpeed);
|
||||
_moveTarget.start();
|
||||
_targetAnimation = skybrowser::Animation(start, galacticCoords, angle / targetSpeed);
|
||||
_targetAnimation.start();
|
||||
_targetIsAnimating = true;
|
||||
}
|
||||
|
||||
@@ -307,9 +352,9 @@ void TargetBrowserPair::centerTargetOnScreen() {
|
||||
startAnimation(viewDirection, currentFov);
|
||||
}
|
||||
|
||||
double TargetBrowserPair::targetRoll() {
|
||||
double TargetBrowserPair::targetRoll() const {
|
||||
// To remove the lag effect when moving the camera while having a locked
|
||||
// target, send the locked coordinates to wwt
|
||||
// target, send the locked coordinates to wwt
|
||||
glm::dvec3 normal = glm::normalize(
|
||||
_targetNode->worldPosition() -
|
||||
global::navigationHandler->camera()->positionVec3()
|
||||
@@ -324,10 +369,6 @@ double TargetBrowserPair::targetRoll() {
|
||||
return skybrowser::targetRoll(up, normal);
|
||||
}
|
||||
|
||||
bool TargetBrowserPair::hasFinishedFading() const {
|
||||
return !_fadeBrowser.isAnimating() && !_fadeTarget.isAnimating();
|
||||
}
|
||||
|
||||
bool TargetBrowserPair::isFacingCamera() const {
|
||||
return _browser->isFacingCamera();
|
||||
}
|
||||
@@ -344,15 +385,6 @@ ScreenSpaceSkyBrowser* TargetBrowserPair::browser() const {
|
||||
return _browser;
|
||||
}
|
||||
|
||||
void TargetBrowserPair::incrementallyFade() {
|
||||
if (_fadeBrowser.isAnimating()) {
|
||||
_browser->setOpacity(_fadeBrowser.getNewValue());
|
||||
}
|
||||
if (_fadeTarget.isAnimating()) {
|
||||
_targetRenderable->setOpacity(_fadeTarget.getNewValue());
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const TargetBrowserPair& lhs, const TargetBrowserPair& rhs) {
|
||||
return lhs._targetNode == rhs._targetNode && lhs._browser == rhs._browser;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/navigation/navigationhandler.h>
|
||||
#include <ghoul/misc/easing.h>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
#include <cmath>
|
||||
|
||||
@@ -173,9 +174,9 @@ glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate) {
|
||||
glm::dvec2 fovWindow() {
|
||||
// OpenSpace FOV
|
||||
glm::dvec2 windowDim = glm::dvec2(global::windowDelegate->currentWindowSize());
|
||||
double windowRatio = windowDim.y / windowDim.x;
|
||||
double ratio = windowDim.y / windowDim.x;
|
||||
double hFov = global::windowDelegate->getHorizFieldOfView();
|
||||
glm::dvec2 OpenSpaceFOV = glm::dvec2(hFov, hFov * windowRatio);
|
||||
glm::dvec2 OpenSpaceFOV = glm::dvec2(hFov, hFov * ratio);
|
||||
return OpenSpaceFOV;
|
||||
}
|
||||
|
||||
@@ -216,7 +217,7 @@ float Animation<float>::getNewValue() {
|
||||
}
|
||||
else {
|
||||
float percentage = static_cast<float>(percentageSpent());
|
||||
float diff = static_cast<float>((_goal - _start) * easeOutExpo(percentage));
|
||||
float diff = static_cast<float>((_goal - _start) * ghoul::exponentialEaseOut(percentage));
|
||||
return _start + diff;
|
||||
}
|
||||
}
|
||||
@@ -227,7 +228,7 @@ double Animation<double>::getNewValue() {
|
||||
}
|
||||
else {
|
||||
double percentage = percentageSpent();
|
||||
double diff = (_goal - _start) * easeOutExpo(percentage);
|
||||
double diff = (_goal - _start) * ghoul::exponentialEaseOut(percentage);
|
||||
return _start + diff;
|
||||
}
|
||||
}
|
||||
@@ -236,8 +237,8 @@ glm::dmat4 Animation<glm::dvec3>::getRotationMatrix() {
|
||||
if (!isAnimating()) {
|
||||
return glm::dmat4(1.0);
|
||||
}
|
||||
|
||||
double percentage = easeInOutSine(percentageSpent());
|
||||
|
||||
double percentage = ghoul::sineEaseInOut(percentageSpent());
|
||||
double increment = percentage - _lastPercentage;
|
||||
_lastPercentage = percentage;
|
||||
|
||||
@@ -256,7 +257,7 @@ glm::dvec3 Animation<glm::dvec3>::getNewValue() {
|
||||
glm::dmat4 rotMat = skybrowser::incrementalAnimationMatrix(
|
||||
glm::normalize(_start),
|
||||
glm::normalize(_goal),
|
||||
easeOutExpo(percentageSpent())
|
||||
ghoul::exponentialEaseOut(percentageSpent())
|
||||
);
|
||||
// Rotate direction
|
||||
return glm::dvec3(rotMat * glm::dvec4(_start, 1.0));;
|
||||
|
||||
@@ -42,21 +42,30 @@ WwtCommunicator::WwtCommunicator(const ghoul::Dictionary& dictionary)
|
||||
|
||||
WwtCommunicator::~WwtCommunicator() {}
|
||||
|
||||
void WwtCommunicator::displayImage(const std::string& url, int i) {
|
||||
void WwtCommunicator::selectImage(const std::string& url, int i) {
|
||||
// Ensure there are no duplicates
|
||||
auto it = std::find(_selectedImages.begin(), _selectedImages.end(), i);
|
||||
auto it = findSelectedImage(i);
|
||||
|
||||
if (it == _selectedImages.end()) {
|
||||
// Push newly selected image to front
|
||||
_selectedImages.push_front(i);
|
||||
// Index of image is used as layer ID as it is unique in the image data set
|
||||
sendMessageToWwt(addImageMessage(std::to_string(i), url));
|
||||
sendMessageToWwt(setImageOpacityMessage(std::to_string(i), 1.0));
|
||||
_selectedImages.push_front(std::pair<int, double>(i, 1.0));
|
||||
|
||||
// If wwt has not loaded the collection yet, wait with passing the message
|
||||
if (_isImageCollectionLoaded) {
|
||||
addImageLayerToWwt(url, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WwtCommunicator::addImageLayerToWwt(const std::string& url, int i) {
|
||||
// Index of image is used as layer ID as it is unique in the image data set
|
||||
sendMessageToWwt(addImageMessage(std::to_string(i), url));
|
||||
sendMessageToWwt(setImageOpacityMessage(std::to_string(i), 1.0));
|
||||
}
|
||||
|
||||
void WwtCommunicator::removeSelectedImage(int i) {
|
||||
// Remove from selected list
|
||||
auto it = std::find(_selectedImages.begin(), _selectedImages.end(), i);
|
||||
auto it = findSelectedImage(i);
|
||||
|
||||
if (it != _selectedImages.end()) {
|
||||
_selectedImages.erase(it);
|
||||
@@ -69,8 +78,20 @@ void WwtCommunicator::sendMessageToWwt(const ghoul::Dictionary& msg) const {
|
||||
executeJavascript(script);
|
||||
}
|
||||
|
||||
const std::deque<int>& WwtCommunicator::getSelectedImages() const {
|
||||
return _selectedImages;
|
||||
std::vector<int> WwtCommunicator::selectedImages() const {
|
||||
std::vector<int> selectedImagesVector;
|
||||
for (const std::pair<int, double>& image : _selectedImages) {
|
||||
selectedImagesVector.push_back(image.first);
|
||||
}
|
||||
return selectedImagesVector;
|
||||
}
|
||||
|
||||
std::vector<double> WwtCommunicator::opacities() const {
|
||||
std::vector<double> opacities;
|
||||
for (const std::pair<int, double>& image : _selectedImages) {
|
||||
opacities.push_back(image.second);
|
||||
}
|
||||
return opacities;
|
||||
}
|
||||
|
||||
void WwtCommunicator::setTargetRoll(double roll) {
|
||||
@@ -88,10 +109,6 @@ void WwtCommunicator::setWebpageBorderColor(glm::ivec3 color) const {
|
||||
executeJavascript(scr);
|
||||
}
|
||||
|
||||
void WwtCommunicator::setIsSyncedWithWwt(bool isSynced) {
|
||||
_isSyncedWithWwt = isSynced;
|
||||
}
|
||||
|
||||
void WwtCommunicator::setEquatorialAim(glm::dvec2 equatorial) {
|
||||
_equatorialAim = std::move(equatorial);
|
||||
_equatorialAimIsDirty = true;
|
||||
@@ -102,14 +119,6 @@ void WwtCommunicator::setBorderColor(glm::ivec3 color) {
|
||||
_borderColorIsDirty = true;
|
||||
}
|
||||
|
||||
void WwtCommunicator::highlight(const glm::ivec3& addition) const {
|
||||
setWebpageBorderColor(_borderColor + addition);
|
||||
}
|
||||
|
||||
void WwtCommunicator::removeHighlight(const glm::ivec3& removal) const {
|
||||
setWebpageBorderColor(_borderColor - removal);
|
||||
}
|
||||
|
||||
void WwtCommunicator::updateBorderColor() const {
|
||||
setWebpageBorderColor(_borderColor);
|
||||
}
|
||||
@@ -125,8 +134,16 @@ glm::dvec2 WwtCommunicator::fieldsOfView() const {
|
||||
return browserFov;
|
||||
}
|
||||
|
||||
bool WwtCommunicator::hasLoadedImages() const {
|
||||
return _hasLoadedImages;
|
||||
bool WwtCommunicator::isImageCollectionLoaded() const {
|
||||
return _isImageCollectionLoaded;
|
||||
}
|
||||
|
||||
std::deque<std::pair<int, double>>::iterator WwtCommunicator::findSelectedImage(int i) {
|
||||
auto it = std::find_if(_selectedImages.begin(), _selectedImages.end(),
|
||||
[i](std::pair<int, double>& pair) {
|
||||
return (pair.first == i);
|
||||
});
|
||||
return it;
|
||||
}
|
||||
|
||||
glm::dvec2 WwtCommunicator::equatorialAim() const {
|
||||
@@ -135,7 +152,7 @@ glm::dvec2 WwtCommunicator::equatorialAim() const {
|
||||
|
||||
void WwtCommunicator::setImageOrder(int i, int order) {
|
||||
// Find in selected images list
|
||||
auto current = std::find(_selectedImages.begin(), _selectedImages.end(), i);
|
||||
auto current = findSelectedImage(i);
|
||||
auto target = _selectedImages.begin() + order;
|
||||
|
||||
// Make sure the image was found in the list
|
||||
@@ -150,23 +167,26 @@ void WwtCommunicator::setImageOrder(int i, int order) {
|
||||
}
|
||||
|
||||
void WwtCommunicator::loadImageCollection(const std::string& collection) {
|
||||
sendMessageToWwt(loadCollectionMessage(collection));
|
||||
_hasLoadedImages = true;
|
||||
if (!_isImageCollectionLoaded) {
|
||||
sendMessageToWwt(loadCollectionMessage(collection));
|
||||
}
|
||||
}
|
||||
|
||||
void WwtCommunicator::setImageOpacity(int i, float opacity) const {
|
||||
void WwtCommunicator::setImageOpacity(int i, float opacity) {
|
||||
auto it = findSelectedImage(i);
|
||||
it->second = opacity;
|
||||
|
||||
ghoul::Dictionary msg = setImageOpacityMessage(std::to_string(i), opacity);
|
||||
sendMessageToWwt(msg);
|
||||
}
|
||||
|
||||
void WwtCommunicator::hideChromeInterface(bool shouldHide) const {
|
||||
void WwtCommunicator::hideChromeInterface() const {
|
||||
std::string script = "sendMessageToWWT({event : \"modify_settings\", "
|
||||
"settings : [[\"hideAllChrome\", true]], target: \"app\"});";
|
||||
executeJavascript(script);
|
||||
}
|
||||
|
||||
void WwtCommunicator::update() {
|
||||
Browser::update();
|
||||
// Cap how messages are passed
|
||||
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
|
||||
std::chrono::system_clock::duration timeSinceLastUpdate = now - _lastUpdateTime;
|
||||
@@ -182,10 +202,14 @@ void WwtCommunicator::update() {
|
||||
}
|
||||
_lastUpdateTime = std::chrono::system_clock::now();
|
||||
}
|
||||
if (_shouldReload) {
|
||||
_isImageCollectionLoaded = false;
|
||||
}
|
||||
Browser::update();
|
||||
}
|
||||
|
||||
void WwtCommunicator::setHasLoadedImages(bool isLoaded) {
|
||||
_hasLoadedImages = isLoaded;
|
||||
void WwtCommunicator::setImageCollectionIsLoaded(bool isLoaded) {
|
||||
_isImageCollectionLoaded = isLoaded;
|
||||
}
|
||||
|
||||
void WwtCommunicator::setIdInBrowser(const std::string& id) const {
|
||||
@@ -207,7 +231,7 @@ ghoul::Dictionary WwtCommunicator::moveCameraMessage(const glm::dvec2& celestCoo
|
||||
bool shouldMoveInstantly) const
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
|
||||
|
||||
ghoul::Dictionary msg;
|
||||
msg.setValue("event", "center_on_coordinates"s);
|
||||
msg.setValue("ra", celestCoords.x);
|
||||
@@ -220,7 +244,7 @@ ghoul::Dictionary WwtCommunicator::moveCameraMessage(const glm::dvec2& celestCoo
|
||||
|
||||
ghoul::Dictionary WwtCommunicator::loadCollectionMessage(const std::string& url) const {
|
||||
using namespace std::string_literals;
|
||||
|
||||
|
||||
ghoul::Dictionary msg;
|
||||
msg.setValue("event", "load_image_collection"s);
|
||||
msg.setValue("url", url);
|
||||
@@ -230,7 +254,7 @@ ghoul::Dictionary WwtCommunicator::loadCollectionMessage(const std::string& url)
|
||||
|
||||
ghoul::Dictionary WwtCommunicator::setForegroundMessage(const std::string& name) const {
|
||||
using namespace std::string_literals;
|
||||
|
||||
|
||||
ghoul::Dictionary msg;
|
||||
msg.setValue("event", "set_foreground_by_name"s);
|
||||
msg.setValue("name", name);
|
||||
@@ -241,7 +265,7 @@ ghoul::Dictionary WwtCommunicator::addImageMessage(const std::string& id,
|
||||
const std::string& url) const
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
|
||||
|
||||
ghoul::Dictionary msg;
|
||||
msg.setValue("event", "image_layer_create"s);
|
||||
msg.setValue("id", id);
|
||||
@@ -253,7 +277,7 @@ ghoul::Dictionary WwtCommunicator::addImageMessage(const std::string& id,
|
||||
|
||||
ghoul::Dictionary WwtCommunicator::removeImageMessage(const std::string& imageId) const {
|
||||
using namespace std::string_literals;
|
||||
|
||||
|
||||
ghoul::Dictionary msg;
|
||||
msg.setValue("event", "image_layer_remove"s);
|
||||
msg.setValue("id", imageId);
|
||||
@@ -264,7 +288,7 @@ ghoul::Dictionary WwtCommunicator::setImageOpacityMessage(const std::string& ima
|
||||
double opacity) const
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
|
||||
|
||||
ghoul::Dictionary msg;
|
||||
msg.setValue("event", "image_layer_set"s);
|
||||
msg.setValue("id", imageId);
|
||||
@@ -278,7 +302,7 @@ ghoul::Dictionary WwtCommunicator::setLayerOrderMessage(const std::string& id, i
|
||||
// The lower the layer order, the more towards the back the image is placed
|
||||
// 0 is the background
|
||||
using namespace std::string_literals;
|
||||
|
||||
|
||||
ghoul::Dictionary msg;
|
||||
msg.setValue("event", "image_layer_order"s);
|
||||
msg.setValue("id", id);
|
||||
|
||||
@@ -520,35 +520,26 @@ bool RenderableFluxNodes::isReady() const {
|
||||
|
||||
void RenderableFluxNodes::populateStartTimes() {
|
||||
std::string timeFile;
|
||||
std::string fileType;
|
||||
for (const std::string& filePath : _binarySourceFiles) {
|
||||
timeFile = filePath;
|
||||
|
||||
if (filePath.substr(filePath.find_last_of(".") + 1) == "csv") {
|
||||
fileType = "csv";
|
||||
timeFile = filePath;
|
||||
break;
|
||||
}
|
||||
else if (filePath.substr(filePath.find_last_of(".") + 1) == "dat") {
|
||||
fileType = "dat";
|
||||
timeFile = filePath;
|
||||
break;
|
||||
}
|
||||
else if (filePath.substr(filePath.find_last_of(".") + 1) == "txt") {
|
||||
fileType = "txt";
|
||||
timeFile = filePath;
|
||||
break;
|
||||
}
|
||||
//if no file extention but word "time" in file name
|
||||
else if (filePath.find("time") != std::string::npos &&
|
||||
filePath.find(".") == std::string::npos)
|
||||
{
|
||||
timeFile = filePath;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
LERROR(fmt::format("Error in file type or naming of file '{}'. ",
|
||||
"Time meta file supports csv, dat, txt or without file extention ",
|
||||
"(but then have to include 'time' in filename)", filePath
|
||||
));
|
||||
timeFile.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (timeFile.empty()) {
|
||||
@@ -750,6 +741,8 @@ void RenderableFluxNodes::update(const UpdateData& data) {
|
||||
if (isInInterval) {
|
||||
const size_t nextIdx = _activeTriggerTimeIndex + 1;
|
||||
if (
|
||||
// true => we were not in an interval the previous frame but now we are
|
||||
_activeTriggerTimeIndex == -1 ||
|
||||
// true => We stepped back to a time represented by another state
|
||||
currentTime < _startTimes[_activeTriggerTimeIndex] ||
|
||||
// true => We stepped forward to a time represented by another state
|
||||
|
||||
@@ -371,21 +371,24 @@ RenderableOrbitalKepler::RenderableOrbitalKepler(const ghoul::Dictionary& dict)
|
||||
|
||||
const Parameters p = codegen::bake<Parameters>(dict);
|
||||
|
||||
_path = p.path;
|
||||
_path.onChange(_reinitializeTrailBuffers);
|
||||
addProperty(_opacity);
|
||||
|
||||
_segmentQuality = static_cast<unsigned int>(p.segmentQuality);
|
||||
_segmentQuality.onChange(_reinitializeTrailBuffers);
|
||||
addProperty(_segmentQuality);
|
||||
|
||||
_appearance.lineColor = p.color;
|
||||
_appearance.lineFade = p.trailFade.value_or(20.f);
|
||||
_appearance.lineWidth = p.lineWidth.value_or(2.f);
|
||||
addPropertySubOwner(_appearance);
|
||||
|
||||
_path = p.path;
|
||||
_path.onChange(_reinitializeTrailBuffers);
|
||||
addProperty(_path);
|
||||
|
||||
_startRenderIdx = p.startRenderIdx.value_or(0);
|
||||
|
||||
_sizeRender = p.renderSize.value_or(0u);
|
||||
|
||||
}
|
||||
|
||||
void RenderableOrbitalKepler::initializeGL() {
|
||||
|
||||
@@ -619,7 +619,14 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary)
|
||||
_colorOption.onChange([&] { _dataIsDirty = true; });
|
||||
addProperty(_colorOption);
|
||||
|
||||
_colorTexturePath.onChange([&] { _colorTextureIsDirty = true; });
|
||||
_colorTexturePath.onChange([&] {
|
||||
if (std::filesystem::exists(_colorTexturePath.value())) {
|
||||
_colorTextureIsDirty = true;
|
||||
}
|
||||
else {
|
||||
LWARNING(fmt::format("File not found: {}", _colorTexturePath));
|
||||
}
|
||||
});
|
||||
_colorTextureFile->setCallback([this]() { _colorTextureIsDirty = true; });
|
||||
addProperty(_colorTexturePath);
|
||||
|
||||
@@ -632,7 +639,14 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary)
|
||||
addProperty(_otherDataRange);
|
||||
|
||||
addProperty(_otherDataColorMapPath);
|
||||
_otherDataColorMapPath.onChange([&]() { _otherDataColorMapIsDirty = true; });
|
||||
_otherDataColorMapPath.onChange([&]() {
|
||||
if (std::filesystem::exists(_otherDataColorMapPath.value())) {
|
||||
_otherDataColorMapIsDirty = true;
|
||||
}
|
||||
else {
|
||||
LWARNING(fmt::format("File not found: {}", _otherDataColorMapPath));
|
||||
}
|
||||
});
|
||||
|
||||
_staticFilterValue = p.staticFilter;
|
||||
_staticFilterReplacementValue =
|
||||
|
||||
@@ -57,12 +57,6 @@ namespace {
|
||||
"This value determines the RGB color for the line."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo LineOpacityInfo = {
|
||||
"Opacity",
|
||||
"Opacity",
|
||||
"This value determines the opacity for the line."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = {
|
||||
"LineWidth",
|
||||
"Line Width",
|
||||
@@ -92,9 +86,6 @@ namespace {
|
||||
// [[codegen::verbatim(LineColorInfo.description)]]
|
||||
std::optional<glm::vec3> color;
|
||||
|
||||
// [[codegen::verbatim(LineOpacityInfo.description)]]
|
||||
std::optional<float> opacity;
|
||||
|
||||
// [[codegen::verbatim(LineWidthInfo.description)]]
|
||||
std::optional<float> lineWidth;
|
||||
|
||||
@@ -125,9 +116,10 @@ RenderableTravelSpeed::RenderableTravelSpeed(const ghoul::Dictionary& dictionary
|
||||
, _indicatorLength(IndicatorLengthInfo, 1, 1, 360)
|
||||
, _fadeLength(FadeLengthInfo, 1, 0, 360)
|
||||
, _lineWidth(LineWidthInfo, 2.f, 1.f, 20.f)
|
||||
, _opacity(LineOpacityInfo, 1.f, 0.f, 1.f)
|
||||
, _lineColor(LineColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f))
|
||||
{
|
||||
addProperty(_opacity);
|
||||
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
setRenderBin(RenderBin::Overlay);
|
||||
|
||||
@@ -135,8 +127,6 @@ RenderableTravelSpeed::RenderableTravelSpeed(const ghoul::Dictionary& dictionary
|
||||
_lineColor.setViewOption(properties::Property::ViewOptions::Color);
|
||||
addProperty(_lineColor);
|
||||
|
||||
_opacity = p.opacity.value_or(_opacity);
|
||||
addProperty(_opacity);
|
||||
|
||||
_lineWidth = p.lineWidth.value_or(_lineWidth);
|
||||
addProperty(_lineWidth);
|
||||
|
||||
@@ -65,7 +65,6 @@ private:
|
||||
properties::IntProperty _indicatorLength;
|
||||
properties::IntProperty _fadeLength;
|
||||
properties::FloatProperty _lineWidth;
|
||||
properties::FloatProperty _opacity;
|
||||
properties::Vec3Property _lineColor;
|
||||
|
||||
struct VertexPositions {
|
||||
|
||||
@@ -145,10 +145,13 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines)
|
||||
Dataset res;
|
||||
|
||||
int nDataValues = 0;
|
||||
int currentLineNumber = 0;
|
||||
|
||||
std::string line;
|
||||
// First phase: Loading the header information
|
||||
while (std::getline(file, line)) {
|
||||
currentLineNumber++;
|
||||
|
||||
// Ignore empty line or commented-out lines
|
||||
if (line.empty() || line[0] == '#') {
|
||||
continue;
|
||||
@@ -280,6 +283,7 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines)
|
||||
// std::getline, we'd miss the first data value line
|
||||
bool isFirst = true;
|
||||
while (isFirst || std::getline(file, line)) {
|
||||
currentLineNumber++;
|
||||
isFirst = false;
|
||||
|
||||
// Ignore empty line or commented-out lines
|
||||
@@ -316,24 +320,39 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines)
|
||||
allZero &= (entry.position == glm::vec3(0.0));
|
||||
|
||||
if (!str.good()) {
|
||||
// Need to subtract one of the line number here as we increase the current
|
||||
// line count in the beginning of the while loop we are currently in
|
||||
throw ghoul::RuntimeError(fmt::format(
|
||||
"Error loading position information out of data line {} in file {}. "
|
||||
"Value was not a number",
|
||||
res.entries.size(), path
|
||||
currentLineNumber - 1, path
|
||||
));
|
||||
}
|
||||
|
||||
entry.data.resize(nDataValues);
|
||||
std::stringstream valueStream;
|
||||
for (int i = 0; i < nDataValues; i += 1) {
|
||||
str >> entry.data[i];
|
||||
allZero &= (entry.data[i] == 0.0);
|
||||
std::string value;
|
||||
str >> value;
|
||||
if (value == "nan" || value == "NaN") {
|
||||
entry.data[i] = std::numeric_limits<float>::quiet_NaN();
|
||||
}
|
||||
else {
|
||||
valueStream.clear();
|
||||
valueStream.str(value);
|
||||
valueStream >> entry.data[i];
|
||||
|
||||
if (!str.good()) {
|
||||
throw ghoul::RuntimeError(fmt::format(
|
||||
"Error loading data value {} out of data line {} in file {}. "
|
||||
"Value was not a number",
|
||||
i, res.entries.size(), path
|
||||
));
|
||||
allZero &= (entry.data[i] == 0.0);
|
||||
if (valueStream.fail()) {
|
||||
// Need to subtract one of the line number here as we increase the
|
||||
// current line count in the beginning of the while loop we are
|
||||
// currently in
|
||||
throw ghoul::RuntimeError(fmt::format(
|
||||
"Error loading data value {} out of data line {} in file {}. "
|
||||
"Value was not a number",
|
||||
i, currentLineNumber - 1, path
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ bool HorizonsTranslation::loadCachedFile(const std::filesystem::path& file) {
|
||||
|
||||
// Read all data in one go
|
||||
std::vector<CacheKeyframe> cacheKeyframes;
|
||||
cacheKeyframes.reserve(nKeyframes);
|
||||
cacheKeyframes.resize(nKeyframes);
|
||||
fileStream.read(
|
||||
reinterpret_cast<char*>(cacheKeyframes.data()),
|
||||
sizeof(CacheKeyframe) * nKeyframes
|
||||
|
||||
@@ -47,7 +47,6 @@ private:
|
||||
std::string _name;
|
||||
std::string _fileName;
|
||||
std::string _spacecraft;
|
||||
std::map<std::string, std::unique_ptr<Decoder>> _fileTranslation;
|
||||
std::vector<std::string> _potentialTargets;
|
||||
};
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ void SpoutMain::saveGLState() {
|
||||
_defaultReadBuffer = static_cast<unsigned int>(buf);
|
||||
|
||||
glGetIntegerv(GL_DRAW_BUFFER0, &buf);
|
||||
_defaultReadBuffer = static_cast<unsigned int>(buf);
|
||||
_defaultDrawBuffer[0] = static_cast<unsigned int>(buf);
|
||||
|
||||
saveGLTextureState();
|
||||
}
|
||||
|
||||
@@ -117,6 +117,10 @@ void HttpSynchronization::cancel() {
|
||||
_state = State::Unsynced;
|
||||
}
|
||||
|
||||
std::string HttpSynchronization::generateUid() {
|
||||
return fmt::format("{}/{}", _identifier, _version);
|
||||
}
|
||||
|
||||
bool HttpSynchronization::trySyncFromUrl(std::string listUrl) {
|
||||
HttpMemoryDownload fileListDownload(std::move(listUrl));
|
||||
fileListDownload.onProgress([&c = _shouldCancel](int64_t, std::optional<int64_t>) {
|
||||
|
||||
@@ -87,6 +87,8 @@ public:
|
||||
/// Cancels any ongoing synchronization of this ResourceSynchronization
|
||||
void cancel() override;
|
||||
|
||||
std::string generateUid() override;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
|
||||
@@ -245,4 +245,8 @@ void UrlSynchronization::cancel() {
|
||||
_state = State::Unsynced;
|
||||
}
|
||||
|
||||
std::string UrlSynchronization::generateUid() {
|
||||
return _identifier;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -73,6 +73,8 @@ public:
|
||||
/// Cancels any ongoing synchronization of this ResourceSynchronization
|
||||
void cancel() override;
|
||||
|
||||
std::string generateUid() override;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
|
||||
@@ -231,10 +231,14 @@ void TouchModule::internalInitialize(const ghoul::Dictionary& /*dictionary*/){
|
||||
|
||||
|
||||
global::callback::preSync->push_back([&]() {
|
||||
if (!_touchActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
_touch.setCamera(global::navigationHandler->camera());
|
||||
_touch.setFocusNode(global::navigationHandler->orbitalNavigator().anchorNode());
|
||||
|
||||
if (processNewInput() && global::windowDelegate->isMaster() && _touchActive) {
|
||||
if (processNewInput() && global::windowDelegate->isMaster()) {
|
||||
_touch.updateStateFromInput(_touchPoints, _lastTouchInputs);
|
||||
}
|
||||
else if (_touchPoints.empty()) {
|
||||
|
||||
@@ -101,34 +101,24 @@ RawVolumeMetadata RawVolumeMetadata::createFromDictionary(
|
||||
}
|
||||
|
||||
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));
|
||||
dict.setValue("Dimensions", glm::dvec3(dimensions));
|
||||
dict.setValue("GridType", gridTypeToString(gridType));
|
||||
|
||||
if (hasDomainUnit) {
|
||||
dict.setValue(KeyDomainUnit, domainUnit);
|
||||
dict.setValue("DomainUnit", domainUnit);
|
||||
}
|
||||
if (hasDomainBounds) {
|
||||
dict.setValue(KeyLowerDomainBound, glm::dvec3(lowerDomainBound));
|
||||
dict.setValue(KeyUpperDomainBound, glm::dvec3(upperDomainBound));
|
||||
dict.setValue("LowerDomainBound", glm::dvec3(lowerDomainBound));
|
||||
dict.setValue("UpperDomainBound", glm::dvec3(upperDomainBound));
|
||||
}
|
||||
|
||||
if (hasValueRange) {
|
||||
dict.setValue(KeyMinValue, static_cast<double>(minValue));
|
||||
dict.setValue(KeyMaxValue, static_cast<double>(maxValue));
|
||||
dict.setValue("MinValue", static_cast<double>(minValue));
|
||||
dict.setValue("MaxValue", static_cast<double>(maxValue));
|
||||
}
|
||||
if (hasDomainUnit) {
|
||||
dict.setValue(KeyValueUnit, valueUnit);
|
||||
dict.setValue("ValueUnit", valueUnit);
|
||||
}
|
||||
|
||||
if (hasTime) {
|
||||
@@ -137,7 +127,7 @@ ghoul::Dictionary RawVolumeMetadata::dictionary() {
|
||||
if (timeString.back() == 'Z') {
|
||||
timeString = timeString.substr(0, timeString.size() - 1);
|
||||
}
|
||||
dict.setValue(KeyTime, std::string(timeString));
|
||||
dict.setValue("Time", std::string(timeString));
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ void BasicVolumeRaycaster::preRaycast(const RaycastData& data,
|
||||
program.setUniform("nClips_" + id, nClips);
|
||||
program.setUniform("clipNormals_" + id, clipNormals);
|
||||
program.setUniform("clipOffsets_" + id, clipOffsets);
|
||||
program.setUniform("opacity_" + id, opacity());
|
||||
program.setUniform("brightness_" + id, brightness());
|
||||
program.setUniform("rNormalization_" + id, _rNormalization);
|
||||
program.setUniform("rUpperBound_" + id, _rUpperBound);
|
||||
}
|
||||
@@ -197,12 +197,12 @@ void BasicVolumeRaycaster::setStepSize(float stepSize) {
|
||||
_stepSize = stepSize;
|
||||
}
|
||||
|
||||
void BasicVolumeRaycaster::setOpacity(float opacity) {
|
||||
_opacity = opacity;
|
||||
void BasicVolumeRaycaster::setBrightness(float brightness) {
|
||||
_brightness = brightness;
|
||||
}
|
||||
|
||||
float BasicVolumeRaycaster::opacity() const {
|
||||
return _opacity;
|
||||
float BasicVolumeRaycaster::brightness() const {
|
||||
return _brightness;
|
||||
}
|
||||
|
||||
void BasicVolumeRaycaster::setRNormalization(float rNormalization) {
|
||||
|
||||
@@ -76,11 +76,12 @@ public:
|
||||
|
||||
void setVolumeTexture(std::shared_ptr<ghoul::opengl::Texture> texture);
|
||||
std::shared_ptr<ghoul::opengl::Texture> volumeTexture() const;
|
||||
void setTransferFunction(std::shared_ptr<TransferFunction> transferFunction);
|
||||
void setTransferFunction(std::shared_ptr<openspace::TransferFunction>
|
||||
transferFunction);
|
||||
|
||||
void setStepSize(float stepSize);
|
||||
float opacity() const;
|
||||
void setOpacity(float opacity);
|
||||
float brightness() const;
|
||||
void setBrightness(float brightness);
|
||||
float rNormalization() const;
|
||||
void setRNormalization(float rNormalization);
|
||||
float rUpperBound() const;
|
||||
@@ -98,7 +99,7 @@ private:
|
||||
BoxGeometry _boundingBox;
|
||||
VolumeGridType _gridType;
|
||||
glm::mat4 _modelTransform = glm::mat4(1.f);
|
||||
float _opacity = 20.f;
|
||||
float _brightness = 1.f;
|
||||
float _rNormalization = 0.f;
|
||||
float _rUpperBound = 1.f;
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@ namespace {
|
||||
constexpr const char* _loggerCat = "RenderableTimeVaryingVolume";
|
||||
|
||||
const float SecondsInOneDay = 60 * 60 * 24;
|
||||
constexpr const float VolumeMaxOpacity = 500;
|
||||
|
||||
static const openspace::properties::Property::PropertyInfo StepSizeInfo = {
|
||||
"StepSize",
|
||||
@@ -104,10 +103,10 @@ namespace {
|
||||
"Lets you scrub through the sequence's time steps."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo OpacityInfo = {
|
||||
"Opacity",
|
||||
"Opacity",
|
||||
"The volumes general opacity."
|
||||
constexpr openspace::properties::Property::PropertyInfo BrightnessInfo = {
|
||||
"Brightness",
|
||||
"Brightness",
|
||||
"The volume renderer's general brightness."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo rNormalizationInfo = {
|
||||
@@ -138,8 +137,8 @@ namespace {
|
||||
// Specifies if you want to invert the volume data at it z-axis.
|
||||
std::optional<bool> invertDataAtZ;
|
||||
|
||||
// [[codegen::verbatim(OpacityInfo.description)]]
|
||||
std::optional<float> opacity;
|
||||
// [[codegen::verbatim(BrightnessInfo.description)]]
|
||||
std::optional<float> brightness;
|
||||
|
||||
// [[codegen::verbatim(StepSizeInfo.description)]]
|
||||
std::optional<float> stepSize;
|
||||
@@ -164,7 +163,7 @@ RenderableTimeVaryingVolume::RenderableTimeVaryingVolume(
|
||||
: Renderable(dictionary)
|
||||
, _gridType(GridTypeInfo, properties::OptionProperty::DisplayType::Dropdown)
|
||||
, _stepSize(StepSizeInfo, 0.02f, 0.001f, 0.1f)
|
||||
, _opacity(OpacityInfo, 10.f, 0.f, VolumeMaxOpacity)
|
||||
, _brightness(BrightnessInfo, 0.33f, 0.f, 1.f)
|
||||
, _rNormalization(rNormalizationInfo, 0.f, 0.f, 2.f)
|
||||
, _rUpperBound(rUpperBoundInfo, 1.f, 0.f, 2.f)
|
||||
, _secondsBefore(SecondsBeforeInfo, 0.f, 0.01f, SecondsInOneDay)
|
||||
@@ -194,10 +193,7 @@ RenderableTimeVaryingVolume::RenderableTimeVaryingVolume(
|
||||
|
||||
_stepSize = p.stepSize.value_or(_stepSize);
|
||||
|
||||
if (p.opacity.has_value()) {
|
||||
_opacity = *p.opacity * VolumeMaxOpacity;
|
||||
}
|
||||
|
||||
_brightness = p.brightness.value_or(_brightness);
|
||||
_secondsBefore = p.secondsBefore.value_or(_secondsBefore);
|
||||
_secondsAfter = p.secondsAfter;
|
||||
|
||||
@@ -211,6 +207,7 @@ RenderableTimeVaryingVolume::RenderableTimeVaryingVolume(
|
||||
_gridType = static_cast<std::underlying_type_t<VolumeGridType>>(gridType);
|
||||
}
|
||||
|
||||
addProperty(_brightness);
|
||||
addProperty(_opacity);
|
||||
}
|
||||
|
||||
@@ -452,7 +449,7 @@ void RenderableTimeVaryingVolume::update(const UpdateData&) {
|
||||
_raycaster->setVolumeTexture(nullptr);
|
||||
}
|
||||
_raycaster->setStepSize(_stepSize);
|
||||
_raycaster->setOpacity(opacity());
|
||||
_raycaster->setBrightness(_brightness * opacity());
|
||||
_raycaster->setRNormalization(_rNormalization);
|
||||
_raycaster->setRUpperBound(_rUpperBound);
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ private:
|
||||
std::shared_ptr<VolumeClipPlanes> _clipPlanes;
|
||||
|
||||
properties::FloatProperty _stepSize;
|
||||
properties::FloatProperty _opacity;
|
||||
properties::FloatProperty _brightness;
|
||||
properties::FloatProperty _rNormalization;
|
||||
properties::FloatProperty _rUpperBound;
|
||||
properties::FloatProperty _secondsBefore;
|
||||
|
||||
@@ -31,8 +31,9 @@ uniform int nClips_#{id};
|
||||
uniform vec3 clipNormals_#{id}[8];
|
||||
uniform vec2 clipOffsets_#{id}[8];
|
||||
|
||||
uniform float opacity_#{id} = 10.0;
|
||||
|
||||
uniform float brightness_#{id} = 1.0;
|
||||
// unitless factor that multiplies with the brightness [0,1] to achieve desired visuals.
|
||||
const float SamplingIntervalReferenceFactor = 500.0;
|
||||
|
||||
// Normalization factor x for radius r [0, 1].
|
||||
// value *= 1/(r^x)
|
||||
@@ -78,8 +79,8 @@ void sample#{id}(vec3 samplePos, vec3 dir, inout vec3 accumulatedColor,
|
||||
vec3 backColor = color.rgb;
|
||||
vec3 backAlpha = color.aaa;
|
||||
|
||||
backColor *= stepSize*opacity_#{id} * clipAlpha;
|
||||
backAlpha *= stepSize*opacity_#{id} * clipAlpha;
|
||||
backColor *= stepSize * brightness_#{id} * SamplingIntervalReferenceFactor * clipAlpha;
|
||||
backAlpha *= stepSize * brightness_#{id} * SamplingIntervalReferenceFactor * clipAlpha;
|
||||
|
||||
backColor = clamp(backColor, 0.0, 1.0);
|
||||
backAlpha = clamp(backAlpha, 0.0, 1.0);
|
||||
|
||||
@@ -42,8 +42,10 @@ void WebBrowserApp::OnContextCreated(CefRefPtr<CefBrowser>, CefRefPtr<CefFrame>,
|
||||
void WebBrowserApp::OnBeforeCommandLineProcessing(const CefString&,
|
||||
CefRefPtr<CefCommandLine> commandLine)
|
||||
{
|
||||
commandLine->AppendSwitch("use-gl=desktop");
|
||||
commandLine->AppendSwitch("ignore-gpu-blacklist");
|
||||
commandLine->AppendSwitch("--enable-gpu-rasterization");
|
||||
commandLine->AppendSwitch("--use-gl=desktop");
|
||||
commandLine->AppendSwitch("--enable-webgl2-compute-context");
|
||||
commandLine->AppendSwitch("ignore-gpu-blocklist");
|
||||
commandLine->AppendSwitch("log-gpu-control-list-decisions");
|
||||
commandLine->AppendSwitch("use-mock-keychain");
|
||||
commandLine->AppendSwitch("enable-begin-frame-scheduling");
|
||||
|
||||
@@ -140,11 +140,6 @@ void WebBrowserModule::internalInitialize(const ghoul::Dictionary& dictionary) {
|
||||
_enabled = dictionary.value<bool>("Enabled");
|
||||
}
|
||||
|
||||
const bool isMaster = global::windowDelegate->isMaster();
|
||||
if (!_enabled || (!isMaster)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LDEBUG(fmt::format("CEF using web helper executable: {}", _webHelperLocation));
|
||||
_cefHost = std::make_unique<CefHost>(_webHelperLocation.string());
|
||||
LDEBUG("Starting CEF... done!");
|
||||
|
||||
Reference in New Issue
Block a user