diff --git a/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h b/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h index 563a0ec5a7..9ff82c4e8b 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h @@ -45,12 +45,21 @@ public: private slots: void parseScript(); + void chooseScripts(); + + /** + * Adds scripts to the _scriptEdit from outside dialogs + * + * \param scripts #std::string scripts to be appended + */ + void appendScriptsToTextfield(std::string scripts); private: void createWidgets(); openspace::Profile& _profile; QTextEdit* _textScripts = nullptr; + QPushButton* _chooseScriptsButton = nullptr; }; #endif // __OPENSPACE_UI_LAUNCHER___ADDITIONALSCRIPTS___H__ diff --git a/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h b/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h index 488b560155..34097a0b2a 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h @@ -58,13 +58,6 @@ public: */ virtual void keyPressEvent(QKeyEvent* evt) override; - /** - * Adds scripts to the _scriptEdit from outside dialogs - * - * \param scripts #std::string scripts to be appended - */ - void appendScriptsToKeybind(const std::string& scripts); - private slots: void listItemSelected(); void listItemAdded(); @@ -76,6 +69,13 @@ private slots: void chooseScripts(); void keySelected(int index); + /** + * Adds scripts to the _scriptEdit from outside dialogs + * + * \param scripts #std::string scripts to be appended + */ + void appendScriptsToKeybind(std::string scripts); + private: void createWidgets(); void transitionFromEditMode(); diff --git a/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h b/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h index 49de2deee8..34a5a0e555 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h @@ -35,10 +35,12 @@ public: /** * Constructor for ScriptlogDialog class * - * \param bindingDialog keybindingDialog that openend this window. * \param parent Pointer to parent Qt widget */ - ScriptlogDialog(KeybindingsDialog* bindingDialog, QWidget* parent); + ScriptlogDialog(QWidget* parent); + +signals: + void scriptsSelected(std::string script); private slots: void saveChosenScripts(); @@ -46,7 +48,6 @@ private slots: private: void createWidgets(); - KeybindingsDialog* _bindingDialog = nullptr; QListWidget* _scriptlogList = nullptr; }; diff --git a/apps/OpenSpace/ext/launcher/src/profile/additionalscriptsdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/additionalscriptsdialog.cpp index 7c584e2f13..6c91f58e1d 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/additionalscriptsdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/additionalscriptsdialog.cpp @@ -25,10 +25,12 @@ #include "profile/additionalscriptsdialog.h" #include "profile/line.h" +#include "profile/scriptlogdialog.h" #include #include #include #include +#include #include #include @@ -61,6 +63,13 @@ void AdditionalScriptsDialog::createWidgets() { _textScripts->setAcceptRichText(false); layout->addWidget(_textScripts, 1); + _chooseScriptsButton = new QPushButton("Choose Scripts"); + connect( + _chooseScriptsButton, &QPushButton::clicked, + this, &AdditionalScriptsDialog::chooseScripts + ); + layout->addWidget(_chooseScriptsButton); + layout->addWidget(new Line); { @@ -89,3 +98,13 @@ void AdditionalScriptsDialog::parseScript() { _profile.setAdditionalScripts(additionalScripts); accept(); } + +void AdditionalScriptsDialog::chooseScripts() { + ScriptlogDialog d(this); + connect(&d, &ScriptlogDialog::scriptsSelected, this, &AdditionalScriptsDialog::appendScriptsToTextfield); + d.exec(); +} + +void AdditionalScriptsDialog::appendScriptsToTextfield(std::string scripts) { + _textScripts->append(QString::fromStdString(std::move(scripts))); +} diff --git a/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp index dc373a6a01..baa366a879 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp @@ -108,8 +108,8 @@ KeybindingsDialog::KeybindingsDialog(Profile& profile, QWidget *parent) transitionFromEditMode(); } -void KeybindingsDialog::appendScriptsToKeybind(const std::string& scripts) { - _scriptEdit->append(QString::fromStdString(scripts)); +void KeybindingsDialog::appendScriptsToKeybind(std::string scripts) { + _scriptEdit->append(QString::fromStdString(std::move(scripts))); } void KeybindingsDialog::createWidgets() { @@ -525,7 +525,9 @@ void KeybindingsDialog::parseSelections() { void KeybindingsDialog::chooseScripts() { _errorMsg->clear(); - ScriptlogDialog(this, this).exec(); + ScriptlogDialog d(this); + connect(&d, &ScriptlogDialog::scriptsSelected, this, &KeybindingsDialog::appendScriptsToKeybind); + d.exec(); } void KeybindingsDialog::keyPressEvent(QKeyEvent* evt) { diff --git a/apps/OpenSpace/ext/launcher/src/profile/scriptlogdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/scriptlogdialog.cpp index dab9689dd8..c82fd8aa57 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/scriptlogdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/scriptlogdialog.cpp @@ -33,10 +33,8 @@ #include #include -ScriptlogDialog::ScriptlogDialog(KeybindingsDialog* bindingDialog, - QWidget* parent) +ScriptlogDialog::ScriptlogDialog(QWidget* parent) : QDialog(parent) - , _bindingDialog(bindingDialog) { setWindowTitle("Scriptlog"); createWidgets(); @@ -93,7 +91,7 @@ void ScriptlogDialog::saveChosenScripts() { chosenScripts += "\n"; } } - _bindingDialog->appendScriptsToKeybind(chosenScripts); + emit scriptsSelected(chosenScripts); accept(); } diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/misc/iss.asset b/data/assets/scene/solarsystem/planets/earth/satellites/misc/iss.asset index a21b3bd1a2..eee82d3659 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/misc/iss.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/misc/iss.asset @@ -24,7 +24,7 @@ local initializeAndAddNodes = function() local iss = { Identifier = "ISS", Parent = transforms.EarthInertial.Identifier, - BoundingSphere = 30, + InteractionSphere = 30, Transform = { Translation = { Type = "TLETranslation", diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/weather/aqua.asset b/data/assets/scene/solarsystem/planets/earth/satellites/weather/aqua.asset index 9ebe43df49..a056478bdf 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/weather/aqua.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/weather/aqua.asset @@ -19,7 +19,7 @@ asset.onInitialize(function () local Aqua = { Identifier = "Aqua", Parent = transforms.EarthInertial.Identifier, - BoundingSphere = 30, + InteractionSphere = 30, Transform = { Translation = { Type = "TLETranslation", diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/weather/snpp.asset b/data/assets/scene/solarsystem/planets/earth/satellites/weather/snpp.asset index 2b251d229d..eeec482047 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/weather/snpp.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/weather/snpp.asset @@ -19,7 +19,7 @@ asset.onInitialize(function () local SNPP = { Identifier = "SNPP", Parent = transforms.EarthInertial.Identifier, - BoundingSphere = 30, + InteractionSphere = 30, Transform = { Translation = { Type = "TLETranslation", diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/weather/terra.asset b/data/assets/scene/solarsystem/planets/earth/satellites/weather/terra.asset index 3d064550ee..8b130ebf9b 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/weather/terra.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/weather/terra.asset @@ -19,7 +19,7 @@ asset.onInitialize(function () local Terra = { Identifier = "Terra", Parent = transforms.EarthInertial.Identifier, - BoundingSphere = 30, + InteractionSphere = 30, Transform = { Translation = { Type = "TLETranslation", diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index 61d64e4c51..05b5cb9b83 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -3,7 +3,7 @@ asset.require('./static_server') local guiCustomization = asset.require('customization/gui') -- Select which commit hashes to use for the frontend and backend -local frontendHash = "02d6b86e40ea4db4bd8755bf7ade22fd9d839785" +local frontendHash = "391f8d3ed74e598a0e8a1b16016324d8f747e18d" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({ diff --git a/ext/ghoul b/ext/ghoul index 9e815e8073..34864556a4 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 9e815e80730916ceeeedf15ef84afd487bba3e09 +Subproject commit 34864556a4f9718d79fc911cb46e23ccef233d24 diff --git a/include/openspace/properties/property.h b/include/openspace/properties/property.h index b0257ef484..b900cf8335 100644 --- a/include/openspace/properties/property.h +++ b/include/openspace/properties/property.h @@ -381,22 +381,21 @@ public: /** * Default view options that can be used in the Property::setViewOption method. The - * values are: Property::ViewOptions::Color = \c color, - * Property::ViewOptions::LightPosition = \c lightPosition + * values are: Property::ViewOptions::Color = \c Color, + * Property::ViewOptions::Logarithmic = \c Logarithmic */ struct ViewOptions { static const char* Color; - static const char* LightPosition; + static const char* Logarithmic; }; /** * This method allows the developer to give hints to the GUI about different * representations for the GUI. The same Property (for example Vec4Property) can be * used in different ways, each requiring a different input method. These values are - * stored in the metaData object using the views. prefix in front of the - * option parameter. See Property::ViewOptions for a default list of - * possible options. As these are only hints, the GUI is free to ignore any suggestion - * by the developer. + * stored in the metaData object under ViewOptions. + * See Property::ViewOptions for a default list of possible options. As these are + * only hints, the GUI is free to ignore any suggestion by the developer. * \param option The view option that should be modified * \param value Determines if the view option should be active (true) or * deactivated (false) diff --git a/include/openspace/rendering/helper.h b/include/openspace/rendering/helper.h index f82fabe5a0..51498da96c 100644 --- a/include/openspace/rendering/helper.h +++ b/include/openspace/rendering/helper.h @@ -61,12 +61,12 @@ void renderBox(const glm::vec2& position, const glm::vec2& size, const glm::vec4 struct Shaders { struct { std::unique_ptr program; - UniformCache(tex, hasTexture, shouldFlipTexture, ortho, color) cache; + UniformCache(tex, hasTexture, shouldFlipTexture, proj, color) cache; } xyuvrgba; struct { std::unique_ptr program; - UniformCache(tex, hasTexture, shouldFlipTexture, ortho, color) cache; + UniformCache(tex, hasTexture, shouldFlipTexture, proj, color) cache; } screenfilling; }; @@ -76,6 +76,14 @@ struct VertexObjects { GLuint vbo; } square; + struct { + GLuint vao; + GLuint vbo; + GLuint ibo; + + int nElements = 64; + } sphere; + struct { GLuint vao; } empty; @@ -108,6 +116,9 @@ std::vector convert(std::vector v); std::vector createRing(int nSegments, float radius, glm::vec4 colors = glm::vec4(1.f)); +std::pair, std::vector> +createSphere(int nSegments, glm::vec3 radii, glm::vec4 colors = glm::vec4(1.f)); + } // namespace openspace::rendering::helper #endif // __OPENSPACE_CORE___HELPER___H__ diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index 3fa96880d4..ca8d52c0e3 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -31,6 +31,7 @@ #include #include #include +#include #include namespace ghoul { class Dictionary; } @@ -75,11 +76,17 @@ public: bool isEnabled() const; bool shouldUpdateIfDisabled() const; - void setBoundingSphere(double boundingSphere); double boundingSphere() const; + double interactionSphere() const; virtual void render(const RenderData& data, RendererTasks& rendererTask); virtual void update(const UpdateData& data); + + // The 'surface' in this case is the interaction sphere of this renderable. In some + // cases (i.e., planets) this corresponds directly to the physical surface, but in + // many cases, models, volumetric data, this will not. Regardless of what the physical + // representation is, the 'surface' is always the sphere around which interaction is + // handled virtual SurfacePositionHandle calculateSurfacePositionHandle( const glm::dvec3& targetModelSpace) const; @@ -98,15 +105,25 @@ public: protected: properties::BoolProperty _enabled; properties::FloatProperty _opacity; - properties::DoubleProperty _boundingSphere; properties::StringProperty _renderableType; - bool _shouldUpdateIfDisabled = false; + void setBoundingSphere(double boundingSphere); void setRenderBinFromOpacity(); void registerUpdateRenderBinFromOpacity(); + double _boundingSphere = 0.0; + double _interactionSphere = 0.0; + SceneGraphNode* _parent = nullptr; + bool _shouldUpdateIfDisabled = false; + private: + // We only want the SceneGraphNode to be able manipulate the parent, so we don't want + // to provide a set method for this. Otherwise, anyone might mess around with our + // parentage and that's no bueno + friend ghoul::mm_unique_ptr SceneGraphNode::createFromDictionary( + const ghoul::Dictionary&); + RenderBin _renderBin = RenderBin::Opaque; }; diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index 879a78a352..d83fda6315 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -36,14 +36,16 @@ #include #include #include +#include #include #include +#include #include -#include //#define Debugging_Core_SceneGraphNode_Indices namespace ghoul { class Dictionary; } +namespace ghoul::opengl { class ProgramObject; } namespace openspace { @@ -127,6 +129,7 @@ public: std::vector children() const; double boundingSphere() const; + double interactionSphere() const; SceneGraphNode* childNode(const std::string& identifier); @@ -143,6 +146,7 @@ private: glm::dmat3 calculateWorldRotation() const; glm::dvec3 calculateWorldScale() const; void computeScreenSpaceData(RenderData& newData); + void renderDebugSphere(const Camera& camera, double size, glm::vec4 color); std::atomic _state = State::Loaded; std::vector> _children; @@ -178,6 +182,7 @@ private: glm::dmat4 _modelTransformCached = glm::dmat4(1.0); properties::DoubleProperty _boundingSphere; + properties::DoubleProperty _interactionSphere; properties::BoolProperty _computeScreenSpaceValues; properties::IVec2Property _screenSpacePosition; properties::BoolProperty _screenVisibility; @@ -189,6 +194,12 @@ private: // are calculated when _computeScreenSpaceValues is true) std::chrono::high_resolution_clock::time_point _lastScreenSpaceUpdateTime; + properties::BoolProperty _showDebugSphere; + static ghoul::opengl::ProgramObject* _debugSphereProgram; + + std::optional _overrideBoundingSphere; + std::optional _overrideInteractionSphere; + #ifdef Debugging_Core_SceneGraphNode_Indices int index = 0; static int nextIndex; diff --git a/include/openspace/util/updatestructures.h b/include/openspace/util/updatestructures.h index 5ea1f1fe5b..00e1f57004 100644 --- a/include/openspace/util/updatestructures.h +++ b/include/openspace/util/updatestructures.h @@ -50,7 +50,7 @@ struct UpdateData { struct RenderData { const Camera& camera; const Time time; - int renderBinMask = -1; + int8_t renderBinMask = -1; TransformData modelTransform; }; diff --git a/modules/atmosphere/rendering/renderableatmosphere.cpp b/modules/atmosphere/rendering/renderableatmosphere.cpp index a2ca9476bf..875605a976 100644 --- a/modules/atmosphere/rendering/renderableatmosphere.cpp +++ b/modules/atmosphere/rendering/renderableatmosphere.cpp @@ -381,6 +381,8 @@ RenderableAtmosphere::RenderableAtmosphere(const ghoul::Dictionary& dictionary) _hardShadowsEnabled.onChange(updateWithoutCalculation); addProperty(_hardShadowsEnabled); } + + setBoundingSphere(_planetRadius * 1000.0); } void RenderableAtmosphere::deinitializeGL() { diff --git a/modules/base/rendering/grids/renderablegrid.cpp b/modules/base/rendering/grids/renderablegrid.cpp index 1f364157f1..c79f5785dc 100644 --- a/modules/base/rendering/grids/renderablegrid.cpp +++ b/modules/base/rendering/grids/renderablegrid.cpp @@ -92,7 +92,7 @@ RenderableGrid::RenderableGrid(const ghoul::Dictionary& dictionary) , _color(ColorInfo, glm::vec3(0.5f), glm::vec3(0.f), glm::vec3(1.f)) , _segments(SegmentsInfo, glm::uvec2(10), glm::uvec2(1), glm::uvec2(200)) , _lineWidth(LineWidthInfo, 0.5f, 1.f, 20.f) - , _size(SizeInfo, glm::vec2(1e20f), glm::vec2(1.f), glm::vec2(1e35f)) + , _size(SizeInfo, glm::vec2(1e10f), glm::vec2(1.f), glm::vec2(1e20f)) { const Parameters p = codegen::bake(dictionary); @@ -110,6 +110,7 @@ RenderableGrid::RenderableGrid(const ghoul::Dictionary& dictionary) _lineWidth = p.lineWidth.value_or(_lineWidth); addProperty(_lineWidth); + _size.setViewOption(properties::Property::ViewOptions::Logarithmic); _size = p.size.value_or(_size); _size.onChange([&]() { _gridIsDirty = true; }); addProperty(_size); diff --git a/modules/base/rendering/renderabledisc.cpp b/modules/base/rendering/renderabledisc.cpp index d15ed1deb9..ca17160453 100644 --- a/modules/base/rendering/renderabledisc.cpp +++ b/modules/base/rendering/renderabledisc.cpp @@ -99,6 +99,7 @@ RenderableDisc::RenderableDisc(const ghoul::Dictionary& dictionary) _texturePath.onChange([&]() { _texture->loadFromFile(_texturePath); }); addProperty(_texturePath); + _size.setViewOption(properties::Property::ViewOptions::Logarithmic); _size = p.size.value_or(_size); setBoundingSphere(_size); _size.onChange([&]() { _planeIsDirty = true; }); diff --git a/modules/base/rendering/renderablemodel.cpp b/modules/base/rendering/renderablemodel.cpp index ba55aa2896..f7003a17cb 100644 --- a/modules/base/rendering/renderablemodel.cpp +++ b/modules/base/rendering/renderablemodel.cpp @@ -690,7 +690,7 @@ void RenderableModel::update(const UpdateData& data) { switch (_animationMode) { case AnimationMode::LoopFromStart: // Start looping from the start time - // s//// + // s//// ... relativeTime = std::fmod(now - startTime, duration); break; case AnimationMode::LoopInfinitely: @@ -699,7 +699,7 @@ void RenderableModel::update(const UpdateData& data) { // true modulo function, it just calculates the remainder of the division // which can be negative. To make it true modulo it is bumped up to // positive values when it is negative - // //s// + // //s// ... relativeTime = std::fmod(now - startTime, duration); if (relativeTime < 0.0) { relativeTime += duration; @@ -711,14 +711,14 @@ void RenderableModel::update(const UpdateData& data) { // goes back to its initial position before starting again. Avoids a // visible jump from the last position to the first position when loop // starts again - // s/\/\/\/\ + // s/\/\/\/\ ... relativeTime = duration - abs(fmod(now - startTime, 2 * duration) - duration); break; case AnimationMode::BounceInfinitely: { // Bounce both before and after the start time where the model is // in the initial position at the start time - // /\/\s/\/\ + // /\/\s/\/\ ... double modulo = fmod(now - startTime, 2 * duration); if (modulo < 0.0) { modulo += 2 * duration; diff --git a/modules/base/rendering/renderablenodeline.cpp b/modules/base/rendering/renderablenodeline.cpp index b8eaed01d6..0c6de14407 100644 --- a/modules/base/rendering/renderablenodeline.cpp +++ b/modules/base/rendering/renderablenodeline.cpp @@ -127,6 +127,7 @@ RenderableNodeLine::RenderableNodeLine(const ghoul::Dictionary& dictionary) addProperty(_end); _lineColor = p.color.value_or(_lineColor); + _lineColor.setViewOption(properties::Property::ViewOptions::Color); addProperty(_lineColor); _lineWidth = p.lineWidth.value_or(_lineWidth); diff --git a/modules/base/rendering/renderableplane.cpp b/modules/base/rendering/renderableplane.cpp index 0e10ee8f2a..a029a4f576 100644 --- a/modules/base/rendering/renderableplane.cpp +++ b/modules/base/rendering/renderableplane.cpp @@ -153,9 +153,11 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary) } _multiplyColor = p.multiplyColor.value_or(_multiplyColor); + _multiplyColor.setViewOption(properties::Property::ViewOptions::Color); addProperty(_billboard); + _size.setViewOption(properties::Property::ViewOptions::Logarithmic); addProperty(_size); _size.onChange([this](){ _planeIsDirty = true; }); diff --git a/modules/base/rendering/renderablesphere.cpp b/modules/base/rendering/renderablesphere.cpp index 4f20d37fc2..0dae86d42c 100644 --- a/modules/base/rendering/renderablesphere.cpp +++ b/modules/base/rendering/renderablesphere.cpp @@ -215,8 +215,12 @@ RenderableSphere::RenderableSphere(const ghoul::Dictionary& dictionary) } addProperty(_orientation); + _size.setViewOption(properties::Property::ViewOptions::Logarithmic); + _size.onChange([this]() { + setBoundingSphere(_size); + _sphereIsDirty = true; + }); addProperty(_size); - _size.onChange([this]() { _sphereIsDirty = true; }); addProperty(_segments); _segments.onChange([this]() { _sphereIsDirty = true; }); @@ -257,6 +261,7 @@ RenderableSphere::RenderableSphere(const ghoul::Dictionary& dictionary) setRenderBin(Renderable::RenderBin::Background); } + setBoundingSphere(_size); setRenderBinFromOpacity(); } diff --git a/modules/base/rendering/renderabletrail.cpp b/modules/base/rendering/renderabletrail.cpp index daab021b50..889772bc58 100644 --- a/modules/base/rendering/renderabletrail.cpp +++ b/modules/base/rendering/renderabletrail.cpp @@ -204,6 +204,7 @@ RenderableTrail::Appearance::Appearance() { RenderingModeLinesPoints, "Lines+Points" } }); + lineColor.setViewOption(properties::Property::ViewOptions::Color); addProperty(lineColor); addProperty(useLineFade); addProperty(lineFade); diff --git a/modules/base/translation/statictranslation.cpp b/modules/base/translation/statictranslation.cpp index 7cdaa8cee6..b4987cccf3 100644 --- a/modules/base/translation/statictranslation.cpp +++ b/modules/base/translation/statictranslation.cpp @@ -58,6 +58,7 @@ StaticTranslation::StaticTranslation() glm::dvec3(std::numeric_limits::max()) ) { + _position.setViewOption(properties::Property::ViewOptions::Logarithmic); addProperty(_position); _position.onChange([this]() { diff --git a/modules/debugging/rendering/renderabledebugplane.cpp b/modules/debugging/rendering/renderabledebugplane.cpp index 723458ed8a..335e48b3b7 100644 --- a/modules/debugging/rendering/renderabledebugplane.cpp +++ b/modules/debugging/rendering/renderabledebugplane.cpp @@ -116,12 +116,13 @@ RenderableDebugPlane::RenderableDebugPlane(const ghoul::Dictionary& dictionary) _texture = p.texture.value_or(_texture); addProperty(_texture); - + + _size.setViewOption(properties::Property::ViewOptions::Logarithmic); _size.onChange([this](){ _planeIsDirty = true; }); _size = p.size.value_or(_size); setBoundingSphere(_size); addProperty(_size); - + _billboard = p.billboard.value_or(_billboard); addProperty(_billboard); diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp index 01a28f5214..3da6f82553 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp +++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp @@ -767,31 +767,6 @@ void RenderableBillboardsCloud::renderLabels(const RenderData& data, const glm::dvec3& orthoUp, float fadeInVariable) { - float scale = 0.f; - switch (_unit) { - case Meter: - scale = 1.f; - break; - case Kilometer: - scale = 1e3f; - break; - case Parsec: - scale = static_cast(PARSEC); - break; - case Kiloparsec: - scale = static_cast(1e3 * PARSEC); - break; - case Megaparsec: - scale = static_cast(1e6 * PARSEC); - break; - case Gigaparsec: - scale = static_cast(1e9 * PARSEC); - break; - case GigalightYears: - scale = static_cast(306391534.73091 * PARSEC); - break; - } - glm::vec4 textColor = glm::vec4( glm::vec3(_textColor), _textOpacity * fadeInVariable @@ -813,7 +788,7 @@ void RenderableBillboardsCloud::renderLabels(const RenderData& data, for (const std::pair& pair : _labelData) { //glm::vec3 scaledPos(_transformationMatrix * glm::dvec4(pair.first, 1.0)); glm::vec3 scaledPos(pair.first); - scaledPos *= scale; + scaledPos *= unitToMeter(_unit); ghoul::fontrendering::FontRenderer::defaultProjectionRenderer().render( *_font, scaledPos, @@ -825,36 +800,11 @@ void RenderableBillboardsCloud::renderLabels(const RenderData& data, } void RenderableBillboardsCloud::render(const RenderData& data, RendererTasks&) { - float scale = 0.f; - switch (_unit) { - case Meter: - scale = 1.f; - break; - case Kilometer: - scale = 1e3f; - break; - case Parsec: - scale = static_cast(PARSEC); - break; - case Kiloparsec: - scale = static_cast(1e3 * PARSEC); - break; - case Megaparsec: - scale = static_cast(1e6 * PARSEC); - break; - case Gigaparsec: - scale = static_cast(1e9 * PARSEC); - break; - case GigalightYears: - scale = static_cast(306391534.73091 * PARSEC); - break; - } - float fadeInVariable = 1.f; if (!_disableFadeInDistance) { float distCamera = static_cast(glm::length(data.camera.positionVec3())); const glm::vec2 fadeRange = _fadeInDistance; - const float a = 1.f / ((fadeRange.y - fadeRange.x) * scale); + const float a = 1.f / ((fadeRange.y - fadeRange.x) * unitToMeter(_unit)); const float b = -(fadeRange.x / (fadeRange.y - fadeRange.x)); const float funcValue = a * distCamera + b; fadeInVariable *= funcValue > 1.f ? 1.f : funcValue; @@ -1488,6 +1438,19 @@ bool RenderableBillboardsCloud::saveCachedFile(const std::string& file) const { return fileStream.good(); } +double RenderableBillboardsCloud::unitToMeter(Unit unit) const { + switch (_unit) { + case Meter: return 1.0; + case Kilometer: return 1e3; + case Parsec: return PARSEC; + case Kiloparsec: return 1000 * PARSEC; + case Megaparsec: return 1e6 * PARSEC; + case Gigaparsec: return 1e9 * PARSEC; + case GigalightYears: return 306391534.73091 * PARSEC; + default: throw ghoul::MissingCaseException(); + } +} + void RenderableBillboardsCloud::createDataSlice() { ZoneScoped @@ -1516,7 +1479,7 @@ void RenderableBillboardsCloud::createDataSlice() { _slicedData.push_back(_fullData[i + 3 + datavarInUse]); }; - auto addPosition = [&](const glm::vec4 &pos) { + auto addPosition = [&](const glm::vec4& pos) { for (int j = 0; j < 4; ++j) { _slicedData.push_back(pos[j]); } @@ -1531,17 +1494,24 @@ void RenderableBillboardsCloud::createDataSlice() { minColorIdx = colorIdx < minColorIdx ? colorIdx : minColorIdx; } + double maxRadius = 0.0; + float biggestCoord = -1.f; for (size_t i = 0; i < _fullData.size(); i += _nValuesPerAstronomicalObject) { - glm::dvec4 transformedPos = _transformationMatrix * glm::dvec4( + glm::vec3 transformedPos = glm::vec3(_transformationMatrix * glm::vec4( _fullData[i + 0], _fullData[i + 1], _fullData[i + 2], 1.0 - ); - // W-normalization - transformedPos /= transformedPos.w; - glm::vec4 position(glm::vec3(transformedPos), static_cast(_unit)); + )); + glm::vec4 position(transformedPos, static_cast(_unit)); + + const double unitMeter = unitToMeter(_unit); + glm::dvec3 p = glm::dvec3(position) * unitMeter; + const double r = glm::length(p); + if (r > maxRadius) { + maxRadius = r; + } if (_hasColorMapFile) { for (int j = 0; j < 4; ++j) { @@ -1623,6 +1593,7 @@ void RenderableBillboardsCloud::createDataSlice() { addPosition(position); } } + setBoundingSphere(maxRadius); _fadeInDistance.setMaxValue(glm::vec2(10.f * biggestCoord)); } diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.h b/modules/digitaluniverse/rendering/renderablebillboardscloud.h index 8bbbf556fc..4f8d9a45f0 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.h +++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.h @@ -76,6 +76,7 @@ private: Gigaparsec = 5, GigalightYears = 6 }; + double unitToMeter(Unit unit) const; void createDataSlice(); void createPolygonTexture(); diff --git a/modules/digitaluniverse/rendering/renderableplanescloud.cpp b/modules/digitaluniverse/rendering/renderableplanescloud.cpp index b190a78757..7d754f9308 100644 --- a/modules/digitaluniverse/rendering/renderableplanescloud.cpp +++ b/modules/digitaluniverse/rendering/renderableplanescloud.cpp @@ -572,35 +572,12 @@ void RenderablePlanesCloud::renderLabels(const RenderData& data, } void RenderablePlanesCloud::render(const RenderData& data, RendererTasks&) { - float scale = 0.f; - switch (_unit) { - case Meter: - scale = 1.f; - break; - case Kilometer: - scale = 1e3f; - break; - case Parsec: - scale = static_cast(PARSEC); - break; - case Kiloparsec: - scale = static_cast(1e3 * PARSEC); - break; - case Megaparsec: - scale = static_cast(1e6 * PARSEC); - break; - case Gigaparsec: - scale = static_cast(1e9 * PARSEC); - break; - case GigalightYears: - scale = static_cast(306391534.73091 * PARSEC); - break; - } + const double scale = unitToMeter(_unit); float fadeInVariable = 1.f; if (!_disableFadeInDistance) { float distCamera = static_cast(glm::length(data.camera.positionVec3())); - distCamera /= scale; + distCamera = static_cast(distCamera / scale); const glm::vec2 fadeRange = _fadeInDistance; //const float a = 1.f / ((fadeRange.y - fadeRange.x) * scale); const float a = 1.f / ((fadeRange.y - fadeRange.x)); @@ -1095,16 +1072,37 @@ bool RenderablePlanesCloud::saveCachedFile(const std::string& file) const { } } +double RenderablePlanesCloud::unitToMeter(Unit unit) const { + switch (_unit) { + case Meter: return 1.0; + case Kilometer: return 1e3; + case Parsec: return PARSEC; + case Kiloparsec: return 1000 * PARSEC; + case Megaparsec: return 1e6 * PARSEC; + case Gigaparsec: return 1e9 * PARSEC; + case GigalightYears: return 306391534.73091 * PARSEC; + default: throw ghoul::MissingCaseException(); + } +} + void RenderablePlanesCloud::createPlanes() { if (_dataIsDirty && _hasSpeckFile) { + const double scale = unitToMeter(_unit); + LDEBUG("Creating planes..."); float maxSize = 0.f; + double maxRadius = 0.0; for (size_t p = 0; p < _fullData.size(); p += _nValuesPerAstronomicalObject) { const glm::vec4 transformedPos = glm::vec4( _transformationMatrix * glm::dvec4(_fullData[p + 0], _fullData[p + 1], _fullData[p + 2], 1.0) ); + const double r = glm::length(glm::dvec3(transformedPos) * scale); + if (r > maxRadius) { + maxRadius = r; + } + // Plane vectors u and v glm::vec4 u = glm::vec4( _transformationMatrix * @@ -1145,31 +1143,6 @@ void RenderablePlanesCloud::createPlanes() { glm::vec4 vertex2 = transformedPos - u + v; glm::vec4 vertex4 = transformedPos + u - v; - float scale = 0.f; - switch (_unit) { - case Meter: - scale = 1.f; - break; - case Kilometer: - scale = 1e3f; - break; - case Parsec: - scale = static_cast(PARSEC); - break; - case Kiloparsec: - scale = static_cast(1e3 * PARSEC); - break; - case Megaparsec: - scale = static_cast(1e6 * PARSEC); - break; - case Gigaparsec: - scale = static_cast(1e9 * PARSEC); - break; - case GigalightYears: - scale = static_cast(306391534.73091 * PARSEC); - break; - } - for (int i = 0; i < 3; ++i) { maxSize = std::max(maxSize, vertex0[i]); maxSize = std::max(maxSize, vertex1[i]); @@ -1252,6 +1225,7 @@ void RenderablePlanesCloud::createPlanes() { _dataIsDirty = false; + setBoundingSphere(maxRadius * _scaleFactor); _fadeInDistance.setMaxValue(glm::vec2(10.f * maxSize)); } diff --git a/modules/digitaluniverse/rendering/renderableplanescloud.h b/modules/digitaluniverse/rendering/renderableplanescloud.h index 2180769f03..9123200e5c 100644 --- a/modules/digitaluniverse/rendering/renderableplanescloud.h +++ b/modules/digitaluniverse/rendering/renderableplanescloud.h @@ -80,6 +80,7 @@ private: Gigaparsec = 5, GigalightYears = 6 }; + double unitToMeter(Unit unit) const; struct PlaneAggregate { int textureIndex; diff --git a/modules/digitaluniverse/rendering/renderablepoints.cpp b/modules/digitaluniverse/rendering/renderablepoints.cpp index 906f6f84f4..96c5420b91 100644 --- a/modules/digitaluniverse/rendering/renderablepoints.cpp +++ b/modules/digitaluniverse/rendering/renderablepoints.cpp @@ -170,6 +170,7 @@ RenderablePoints::RenderablePoints(const ghoul::Dictionary& dictionary) } _pointColor = p.color; + _pointColor.setViewOption(properties::Property::ViewOptions::Color); addProperty(_pointColor); if (p.texture.has_value()) { diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index c0813352a8..024ec67996 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -544,12 +544,12 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) if (p.radii.has_value()) { if (std::holds_alternative(*p.radii)) { _ellipsoid = Ellipsoid(std::get(*p.radii)); - setBoundingSphere(static_cast(_ellipsoid.maximumRadius())); + setBoundingSphere(_ellipsoid.maximumRadius()); } else if (std::holds_alternative(*p.radii)) { const double radius = std::get(*p.radii); _ellipsoid = Ellipsoid({ radius, radius, radius }); - setBoundingSphere(static_cast(_ellipsoid.maximumRadius())); + setBoundingSphere(_ellipsoid.maximumRadius()); } else { throw ghoul::MissingCaseException(); @@ -843,9 +843,14 @@ void RenderableGlobe::update(const UpdateData& data) { ); } - setBoundingSphere(static_cast( - _ellipsoid.maximumRadius() * glm::compMax(data.modelTransform.scale) - )); + double bs = _ellipsoid.maximumRadius() * glm::compMax(data.modelTransform.scale); + if (_hasRings) { + const double ringSize = _ringsComponent.size(); + if (ringSize > bs) { + bs = ringSize; + } + } + setBoundingSphere(bs); glm::dmat4 translation = glm::translate(glm::dmat4(1.0), data.modelTransform.translation); @@ -1831,7 +1836,7 @@ SurfacePositionHandle RenderableGlobe::calculateSurfacePositionHandle( double heightToSurface = getHeight(targetModelSpace); heightToSurface = glm::isnan(heightToSurface) ? 0.0 : heightToSurface; centerToEllipsoidSurface = glm::isnan(glm::length(centerToEllipsoidSurface)) ? - (glm::dvec3(0.0, 1.0, 0.0) * static_cast(boundingSphere())) : + (glm::dvec3(0.0, 1.0, 0.0) * interactionSphere()) : centerToEllipsoidSurface; ellipsoidSurfaceOutDirection = glm::isnan(glm::length(ellipsoidSurfaceOutDirection)) ? glm::dvec3(0.0, 1.0, 0.0) : ellipsoidSurfaceOutDirection; diff --git a/modules/globebrowsing/src/ringscomponent.cpp b/modules/globebrowsing/src/ringscomponent.cpp index 6f0855196e..e59917235b 100644 --- a/modules/globebrowsing/src/ringscomponent.cpp +++ b/modules/globebrowsing/src/ringscomponent.cpp @@ -56,14 +56,14 @@ namespace { constexpr const std::array UniformNames = { "modelViewProjectionMatrix", "textureOffset", "colorFilterValue", "_nightFactor", - "sunPosition", "ringTexture", "shadowMatrix", "shadowMapTexture", + "sunPosition", "ringTexture", "shadowMatrix", "shadowMapTexture", "zFightingPercentage" }; constexpr const std::array UniformNamesAdvancedRings = { "modelViewProjectionMatrix", "textureOffset", "colorFilterValue", "_nightFactor", - "sunPosition", "sunPositionObj", "camPositionObj", "ringTextureFwrd", - "ringTextureBckwrd", "ringTextureUnlit", "ringTextureColor", + "sunPosition", "sunPositionObj", "camPositionObj", "ringTextureFwrd", + "ringTextureBckwrd", "ringTextureUnlit", "ringTextureColor", "ringTextureTransparency", "shadowMatrix", "shadowMapTexture", "zFightingPercentage" }; @@ -251,6 +251,7 @@ void RingsComponent::initialize() { addProperty(_enabled); + _size.setViewOption(properties::Property::ViewOptions::Logarithmic); _size = p.size.value_or(_size); _size.onChange([&]() { _planeIsDirty = true; }); addProperty(_size); @@ -262,7 +263,7 @@ void RingsComponent::initialize() { addProperty(_texturePath); _textureFile->setCallback([&](const File&) { _textureIsDirty = true; }); } - + if (p.textureFwrd.has_value()) { _textureFwrdPath = absPath(p.textureFwrd->string()); _textureFileForwards = std::make_unique(_textureFwrdPath); @@ -423,11 +424,11 @@ void RingsComponent::draw(const RenderData& data, ); _shader->setUniform( - _uniformCacheAdvancedRings.sunPositionObj, + _uniformCacheAdvancedRings.sunPositionObj, sunPositionObjectSpace ); _shader->setUniform( - _uniformCacheAdvancedRings.zFightingPercentage, + _uniformCacheAdvancedRings.zFightingPercentage, _zFightingPercentage ); _shader->setUniform( @@ -438,21 +439,21 @@ void RingsComponent::draw(const RenderData& data, ringTextureFwrdUnit.activate(); _textureForwards->bind(); _shader->setUniform( - _uniformCacheAdvancedRings.ringTextureFwrd, + _uniformCacheAdvancedRings.ringTextureFwrd, ringTextureFwrdUnit ); ringTextureBckwrdUnit.activate(); _textureBackwards->bind(); _shader->setUniform( - _uniformCacheAdvancedRings.ringTextureBckwrd, + _uniformCacheAdvancedRings.ringTextureBckwrd, ringTextureBckwrdUnit ); ringTextureUnlitUnit.activate(); _textureUnlit->bind(); _shader->setUniform( - _uniformCacheAdvancedRings.ringTextureUnlit, + _uniformCacheAdvancedRings.ringTextureUnlit, ringTextureUnlitUnit ); @@ -488,7 +489,7 @@ void RingsComponent::draw(const RenderData& data, ); _shader->setUniform( - _uniformCacheAdvancedRings.camPositionObj, + _uniformCacheAdvancedRings.camPositionObj, _camPositionObjectSpace ); @@ -513,7 +514,7 @@ void RingsComponent::draw(const RenderData& data, _shader->setUniform(_uniformCache.sunPosition, _sunPosition); _shader->setUniform(_uniformCache.zFightingPercentage, _zFightingPercentage); _shader->setUniform( - _uniformCache.modelViewProjectionMatrix, + _uniformCache.modelViewProjectionMatrix, modelViewProjectionTransform ); @@ -533,7 +534,7 @@ void RingsComponent::draw(const RenderData& data, shadowMapUnit.activate(); glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture); _shader->setUniform(_uniformCache.shadowMapTexture, shadowMapUnit); - } + } glEnable(GL_DEPTH_TEST); glEnablei(GL_BLEND, 0); @@ -831,7 +832,7 @@ void RingsComponent::compileShadowShader() { // Uses multiple textures for the Rings // See https://bjj.mmedia.is/data/s_rings/index.html for theory behind it - if (_isAdvancedTextureEnabled) { + if (_isAdvancedTextureEnabled) { _shader = global::renderEngine->buildRenderProgram( "AdvancedRingsProgram", absPath("${MODULE_GLOBEBROWSING}/shaders/advanced_rings_vs.glsl"), @@ -840,8 +841,8 @@ void RingsComponent::compileShadowShader() { ); ghoul::opengl::updateUniformLocations( - *_shader, - _uniformCacheAdvancedRings, + *_shader, + _uniformCacheAdvancedRings, UniformNamesAdvancedRings ); } @@ -866,4 +867,8 @@ bool RingsComponent::isEnabled() const { return _enabled; } +double RingsComponent::size() const { + return _size; +} + } // namespace openspace diff --git a/modules/globebrowsing/src/ringscomponent.h b/modules/globebrowsing/src/ringscomponent.h index a11ef59b18..c19a8565b9 100644 --- a/modules/globebrowsing/src/ringscomponent.h +++ b/modules/globebrowsing/src/ringscomponent.h @@ -71,6 +71,7 @@ public: static documentation::Documentation Documentation(); bool isEnabled() const; + double size() const; private: void loadTexture(); diff --git a/modules/iswa/rendering/datacygnet.cpp b/modules/iswa/rendering/datacygnet.cpp index 8db4963ef7..440be61f3c 100644 --- a/modules/iswa/rendering/datacygnet.cpp +++ b/modules/iswa/rendering/datacygnet.cpp @@ -115,9 +115,17 @@ bool DataCygnet::updateTexture() { } bool texturesReady = false; - const std::vector& selectedOptions = _dataOptions.value(); + const std::set& selectedOptions = _dataOptions; + const std::vector& options = _dataOptions.options(); + std::vector selectedOptionsIndices; + for (const std::string& option : selectedOptions) { + auto it = std::find(options.begin(), options.end(), option); + ghoul_assert(it != options.end(), "Selected option must be in all options"); + int idx = static_cast(std::distance(options.begin(), it)); + selectedOptionsIndices.push_back(idx); + } - for (int option : selectedOptions) { + for (int option : selectedOptionsIndices) { float* values = data[option]; if (!values) { continue; @@ -191,7 +199,16 @@ bool DataCygnet::readyToRender() const { * ghoul::TextureUnit needs to be passed as an argument to both. */ void DataCygnet::setTextureUniforms() { - const std::vector& selectedOptions = _dataOptions.value(); + const std::set& selectedOptions = _dataOptions; + const std::vector& options = _dataOptions.options(); + std::vector selectedOptionsIndices; + for (const std::string& option : selectedOptions) { + auto it = std::find(options.begin(), options.end(), option); + ghoul_assert(it != options.end(), "Selected option must be in all options"); + int idx = static_cast(std::distance(options.begin(), it)); + selectedOptionsIndices.push_back(idx); + } + int activeTextures = std::min(static_cast(selectedOptions.size()), MaxTextures); int activeTransferfunctions = std::min( static_cast(_transferFunctions.size()), @@ -201,7 +218,7 @@ void DataCygnet::setTextureUniforms() { // Set Textures ghoul::opengl::TextureUnit txUnits[MaxTextures]; int j = 0; - for (int option : selectedOptions) { + for (int option : selectedOptionsIndices) { if (_textures[option]) { txUnits[j].activate(); _textures[option]->bind(); @@ -215,7 +232,7 @@ void DataCygnet::setTextureUniforms() { } if (activeTextures > 0 && - selectedOptions.back() >= static_cast(_transferFunctions.size())) + selectedOptionsIndices.back() >= static_cast(_transferFunctions.size())) { activeTransferfunctions = 1; } @@ -230,7 +247,7 @@ void DataCygnet::setTextureUniforms() { _shader->setUniform("transferFunctions[0]", tfUnits[0]); } else { - for (int option : selectedOptions) { + for (int option : selectedOptionsIndices) { if (static_cast(_transferFunctions.size()) >= option) { tfUnits[j].activate(); _transferFunctions[option].bind(); @@ -277,7 +294,7 @@ void DataCygnet::fillOptions(const std::string& source) { ); for (int i = 0; i < static_cast(options.size()); i++) { - _dataOptions.addOption({ i, options[i] }); + _dataOptions.addOption(options[i]); _textures.push_back(nullptr); } @@ -288,7 +305,7 @@ void DataCygnet::fillOptions(const std::string& source) { _dataOptions.setValue(g->dataOptionsValue()); } else { - _dataOptions.setValue(std::vector(1, 0)); + _dataOptions.setValue({ options.front() }); } } @@ -332,7 +349,13 @@ void DataCygnet::subscribeToGroup() { [&](const ghoul::Dictionary& dict) { LDEBUG(identifier() + " Event dataOptionsChanged"); if (dict.hasValue>("dataOptions")) { - _dataOptions = dict.value>("dataOptions"); + std::vector idx = dict.value>("dataOptions"); + std::vector opts = _dataOptions.options(); + std::set selected; + for (int i : idx) { + selected.insert(opts[i]); + } + _dataOptions = selected; } } ); diff --git a/modules/iswa/rendering/iswadatagroup.cpp b/modules/iswa/rendering/iswadatagroup.cpp index 86b8c44510..f8c9f1f954 100644 --- a/modules/iswa/rendering/iswadatagroup.cpp +++ b/modules/iswa/rendering/iswadatagroup.cpp @@ -166,23 +166,23 @@ void IswaDataGroup::registerProperties() { _dataOptions.onChange([this]() { LDEBUG("Group " + identifier() + " published dataOptionsChanged"); ghoul::Dictionary dict; - dict.setValue("dataOptions", _dataOptions.value()); + std::set set = _dataOptions; + std::vector vec(set.begin(), set.end()); + dict.setValue("dataOptions", vec); _groupEvent.publish("dataOptionsChanged", dict); }); } -void IswaDataGroup::registerOptions( - const std::vector& options) -{ +void IswaDataGroup::registerOptions(const std::vector& options) { if (!_registered) { registerProperties(); } if (_dataOptions.options().empty()) { - for (properties::SelectionProperty::Option option : options) { - _dataOptions.addOption({ option.value, option.description }); + for (const std::string& option : options) { + _dataOptions.addOption(option); } - _dataOptions.setValue(std::vector(1, 0)); + _dataOptions.setValue({ options.front() }); } } @@ -198,7 +198,7 @@ void IswaDataGroup::createDataProcessor() { } } -std::vector IswaDataGroup::dataOptionsValue() const { +std::set IswaDataGroup::dataOptionsValue() const { return _dataOptions; } diff --git a/modules/iswa/rendering/iswadatagroup.h b/modules/iswa/rendering/iswadatagroup.h index af34271e1a..ca99873fb1 100644 --- a/modules/iswa/rendering/iswadatagroup.h +++ b/modules/iswa/rendering/iswadatagroup.h @@ -38,9 +38,8 @@ public: IswaDataGroup(std::string name, std::string type); ~IswaDataGroup(); - void registerOptions( - const std::vector& options); - std::vector dataOptionsValue() const; + void registerOptions(const std::vector& options); + std::set dataOptionsValue() const; protected: void registerProperties(); diff --git a/modules/iswa/rendering/iswakameleongroup.cpp b/modules/iswa/rendering/iswakameleongroup.cpp index 1f35bb5d06..a2d719d3ae 100644 --- a/modules/iswa/rendering/iswakameleongroup.cpp +++ b/modules/iswa/rendering/iswakameleongroup.cpp @@ -67,7 +67,7 @@ void IswaKameleonGroup::clearGroup() { clearFieldlines(); } -std::vector IswaKameleonGroup::fieldlineValue() const { +std::set IswaKameleonGroup::fieldlineValue() const { return _fieldlines; } @@ -118,7 +118,7 @@ void IswaKameleonGroup::readFieldlinePaths(const std::string& indexFile) { int i = 0; for (json::iterator it = fieldlines.begin(); it != fieldlines.end(); ++it) { - _fieldlines.addOption({ i, it.key() }); + _fieldlines.addOption(it.key()); _fieldlineState[i] = std::make_tuple( identifier() + "/" + it.key(), it.value(), @@ -137,14 +137,16 @@ void IswaKameleonGroup::readFieldlinePaths(const std::string& indexFile) { } void IswaKameleonGroup::updateFieldlineSeeds() { - const std::vector& options = _fieldlines.value(); + const std::set& options = _fieldlines; + std::vector opts = _fieldlines.options(); // SeedPath == map> using K = int; using V = std::tuple; for (std::pair& seedPath : _fieldlineState) { // if this option was turned off - const auto it = std::find(options.begin(), options.end(), seedPath.first); + std::string o = opts[seedPath.first]; + const auto it = std::find(options.begin(), options.end(), o); if (it == options.end() && std::get<2>(seedPath.second)) { LDEBUG("Removed fieldlines: " + std::get<0>(seedPath.second)); diff --git a/modules/iswa/rendering/iswakameleongroup.h b/modules/iswa/rendering/iswakameleongroup.h index c692ba4d5d..e19ac29a64 100644 --- a/modules/iswa/rendering/iswakameleongroup.h +++ b/modules/iswa/rendering/iswakameleongroup.h @@ -36,7 +36,7 @@ public: virtual void clearGroup() override; - std::vector fieldlineValue() const; + std::set fieldlineValue() const; void setFieldlineInfo(std::string fieldlineIndexFile, std::string kameleonPath); void changeCdf(std::string path); diff --git a/modules/iswa/rendering/kameleonplane.cpp b/modules/iswa/rendering/kameleonplane.cpp index cdbaa9eb1f..78d718fa5b 100644 --- a/modules/iswa/rendering/kameleonplane.cpp +++ b/modules/iswa/rendering/kameleonplane.cpp @@ -112,7 +112,7 @@ KameleonPlane::~KameleonPlane() {} void KameleonPlane::deinitializeGL() { IswaCygnet::deinitialize(); - _fieldlines = std::vector(); + _fieldlines = std::set(); } void KameleonPlane::initializeGL() { @@ -268,16 +268,16 @@ void KameleonPlane::setUniforms() { } void KameleonPlane::updateFieldlineSeeds() { - std::vector selectedOptions = _fieldlines.value(); + std::set selectedOptions = _fieldlines; + std::vector opts = _fieldlines.options(); // seedPath == map> - for (auto& seedPath : _fieldlineState) { + using K = int; + using V = std::tuple; + for (std::pair& seedPath : _fieldlineState) { // if this option was turned off - const auto it = std::find( - selectedOptions.begin(), - selectedOptions.end(), - seedPath.first - ); + std::string o = opts[seedPath.first]; + const auto it = std::find(selectedOptions.begin(), selectedOptions.end(), o); if (it == selectedOptions.end() && std::get<2>(seedPath.second)) { SceneGraphNode* n = global::renderEngine->scene()->sceneGraphNode( std::get<0>(seedPath.second) @@ -336,7 +336,7 @@ void KameleonPlane::readFieldlinePaths(const std::string& indexFile) { const std::string& fullName = identifier(); std::string partName = fullName.substr(0,fullName.find_last_of("-")); for (json::iterator it = fieldlines.begin(); it != fieldlines.end(); ++it) { - _fieldlines.addOption({i, it.key()}); + _fieldlines.addOption(it.key()); _fieldlineState[i] = std::make_tuple( partName + "/" + it.key(), it.value(), diff --git a/modules/iswa/util/dataprocessorjson.cpp b/modules/iswa/util/dataprocessorjson.cpp index 5c02653433..f57bb1c142 100644 --- a/modules/iswa/util/dataprocessorjson.cpp +++ b/modules/iswa/util/dataprocessorjson.cpp @@ -73,11 +73,10 @@ void DataProcessorJson::addDataValues(const std::string& data, std::vector sum(numOptions, 0.f); std::vector> optionValues(numOptions, std::vector()); - const std::vector& options = - dataOptions.options(); + const std::vector& options = dataOptions.options(); for (int i = 0; i < numOptions; ++i) { - const json& row = variables[options[i].description]; + const json& row = variables[options[i]]; // int rowsize = row.size(); for (size_t y = 0; y < row.size(); ++y) { @@ -108,18 +107,23 @@ std::vector DataProcessorJson::processData(const std::string& data, const json& j = json::parse(data); json variables = j["variables"]; - const std::vector& selectedOptions = optionProp; - - const std::vector& options = - optionProp.options(); + const std::set& selectedOptions = optionProp; + const std::vector& options = optionProp.options(); + std::vector selectedOptionsIndices; + for (const std::string& option : selectedOptions) { + auto it = std::find(options.begin(), options.end(), option); + ghoul_assert(it != options.end(), "Selected option must be in all options"); + int idx = static_cast(std::distance(options.begin(), it)); + selectedOptionsIndices.push_back(idx); + } std::vector dataOptions(options.size(), nullptr); - for (int option : selectedOptions) { + for (int option : selectedOptionsIndices) { // @CLEANUP: This memory is very easy to lose and should be replaced by some // other mechanism (std::vector most likely) dataOptions[option] = new float[dimensions.x * dimensions.y] { 0.f }; - json row = variables[options[option].description]; + json row = variables[options[option]]; const int rowsize = static_cast(row.size()); for (int y = 0; y < rowsize; ++y) { @@ -135,7 +139,7 @@ std::vector DataProcessorJson::processData(const std::string& data, } } - calculateFilterValues(selectedOptions); + calculateFilterValues(selectedOptionsIndices); return dataOptions; } diff --git a/modules/iswa/util/dataprocessorkameleon.cpp b/modules/iswa/util/dataprocessorkameleon.cpp index 95b3f6c217..7c0a1b4e1c 100644 --- a/modules/iswa/util/dataprocessorkameleon.cpp +++ b/modules/iswa/util/dataprocessorkameleon.cpp @@ -80,15 +80,14 @@ void DataProcessorKameleon::addDataValues(const std::string& path, std::vector sum(numOptions, 0.f); std::vector> optionValues(numOptions, std::vector()); - const std::vector& options = - dataOptions.options(); + const std::vector& options = dataOptions.options(); const int numValues = static_cast(_dimensions.x * _dimensions.y * _dimensions.z); for (int i = 0; i < numOptions; ++i) { //0.5 to gather interesting values for the normalization/histograms. float* values = _kw->uniformSliceValues( - options[i].description, + options[i], _dimensions, 0.5f ); @@ -120,17 +119,22 @@ std::vector DataProcessorKameleon::processData(const std::string& path, initializeKameleonWrapper(path); } - const std::vector& selectedOptions = optionProp; - - const std::vector& options = - optionProp.options(); + const std::set& selectedOptions = optionProp; + const std::vector& options = optionProp.options(); + std::vector selectedOptionsIndices; + for (const std::string& option : selectedOptions) { + auto it = std::find(options.begin(), options.end(), option); + ghoul_assert(it != options.end(), "Selected option must be in all options"); + int idx = static_cast(std::distance(options.begin(), it)); + selectedOptionsIndices.push_back(idx); + } const int numValues = static_cast(glm::compMul(dimensions)); std::vector dataOptions(numOptions, nullptr); - for (int option : selectedOptions) { + for (int option : selectedOptionsIndices) { dataOptions[option] = _kw->uniformSliceValues( - options[option].description, + options[option], dimensions, _slice ); @@ -141,7 +145,7 @@ std::vector DataProcessorKameleon::processData(const std::string& path, } } - calculateFilterValues(selectedOptions); + calculateFilterValues(selectedOptionsIndices); return dataOptions; } diff --git a/modules/iswa/util/dataprocessortext.cpp b/modules/iswa/util/dataprocessortext.cpp index bcd02f0125..be6d4cb208 100644 --- a/modules/iswa/util/dataprocessortext.cpp +++ b/modules/iswa/util/dataprocessortext.cpp @@ -142,6 +142,10 @@ std::vector DataProcessorText::processData(const std::string& data, properties::SelectionProperty& options, glm::size3_t& dimensions) { + // The update of the selection properties broke this and we don't have the data to + // actually test whether this update works. So if you are getting a crash around here + // this is why + if (data.empty()) { return std::vector(); } @@ -149,11 +153,20 @@ std::vector DataProcessorText::processData(const std::string& data, std::string line; std::stringstream memorystream(data); - const std::vector& selectedOptions = options.value(); + const std::set& selectedOptions = options.value(); + const std::vector& allOptions = options.options(); + std::vector selectedOptionsIndices; std::vector dataOptions(options.options().size(), nullptr); - for (int o : selectedOptions) { - dataOptions[o] = new float[dimensions.x * dimensions.y] { 0.f }; + for (const std::string& o : selectedOptions) { + auto it = std::find(allOptions.begin(), allOptions.end(), o); + ghoul_assert( + it != allOptions.end(), + "Selected option must be in list of all options" + ); + int idx = static_cast(std::distance(allOptions.begin(), it)); + selectedOptionsIndices.push_back(idx); + dataOptions[idx] = new float[dimensions.x * dimensions.y] { 0.f }; } int numValues = 0; @@ -172,11 +185,11 @@ std::vector DataProcessorText::processData(const std::string& data, last = (last > 0)? last : lineSize; const auto it = std::find( - selectedOptions.begin(), - selectedOptions.end(), + selectedOptionsIndices.begin(), + selectedOptionsIndices.end(), option ); - if (option >= 0 && it != selectedOptions.end()) { + if (option >= 0 && it != selectedOptionsIndices.end()) { const float value = std::stof(line.substr(first, last)); dataOptions[option][numValues] = processDataPoint(value, option); } @@ -187,9 +200,10 @@ std::vector DataProcessorText::processData(const std::string& data, numValues++; } - calculateFilterValues(selectedOptions); + calculateFilterValues(selectedOptionsIndices); return dataOptions; +//#endif } } //namespace openspace diff --git a/modules/space/rendering/renderablehabitablezone.cpp b/modules/space/rendering/renderablehabitablezone.cpp index 274fff4b96..d540d75906 100644 --- a/modules/space/rendering/renderablehabitablezone.cpp +++ b/modules/space/rendering/renderablehabitablezone.cpp @@ -143,6 +143,7 @@ RenderableHabitableZone::RenderableHabitableZone(const ghoul::Dictionary& dictio _width.setReadOnly(true); computeZone(); + setBoundingSphere(_size); } void RenderableHabitableZone::render(const RenderData& data, RendererTasks&) { diff --git a/modules/space/rendering/renderableorbitalkepler.cpp b/modules/space/rendering/renderableorbitalkepler.cpp index 291f8daa1b..040354458d 100644 --- a/modules/space/rendering/renderableorbitalkepler.cpp +++ b/modules/space/rendering/renderableorbitalkepler.cpp @@ -476,6 +476,14 @@ void RenderableOrbitalKepler::initializeGL() { _uniformCache.opacity = _programObject->uniformLocation("opacity"); updateBuffers(); + + double maxSemiMajorAxis = 0.0; + for (const KeplerParameters& kp : _data) { + if (kp.semiMajorAxis > maxSemiMajorAxis) { + maxSemiMajorAxis = kp.semiMajorAxis; + } + } + setBoundingSphere(maxSemiMajorAxis * 1000); } void RenderableOrbitalKepler::deinitializeGL() { diff --git a/modules/space/rendering/renderablestars.cpp b/modules/space/rendering/renderablestars.cpp index 1ce1c04748..eefa4ba887 100644 --- a/modules/space/rendering/renderablestars.cpp +++ b/modules/space/rendering/renderablestars.cpp @@ -1486,14 +1486,21 @@ void RenderableStars::createDataSlice(ColorOption option) { -std::numeric_limits::max() ); + double maxRadius = 0.0; + for (size_t i = 0; i < _fullData.size(); i += _nValuesPerStar) { - glm::vec3 position = glm::vec3( + glm::dvec3 position = glm::dvec3( _fullData[i + 0], _fullData[i + 1], _fullData[i + 2] ); position *= openspace::distanceconstants::Parsec; + const double r = glm::length(position); + if (r > maxRadius) { + maxRadius = r; + } + switch (option) { case ColorOption::Color: case ColorOption::FixedColor: @@ -1503,7 +1510,11 @@ void RenderableStars::createDataSlice(ColorOption option) { std::array data; } layout; - layout.value.position = { { position[0], position[1], position[2] } }; + layout.value.position = { { + static_cast(position[0]), + static_cast(position[1]), + static_cast(position[2]) + }}; if (_enableTestGrid) { float sunColor = 0.650f; @@ -1531,7 +1542,11 @@ void RenderableStars::createDataSlice(ColorOption option) { std::array data; } layout; - layout.value.position = { { position[0], position[1], position[2] } }; + layout.value.position = {{ + static_cast(position[0]), + static_cast(position[1]), + static_cast(position[2]) + }}; layout.value.value = _fullData[i + _bvColorArrayPos]; layout.value.luminance = _fullData[i + _lumArrayPos]; @@ -1556,7 +1571,11 @@ void RenderableStars::createDataSlice(ColorOption option) { std::array data; } layout; - layout.value.position = { { position[0], position[1], position[2] } }; + layout.value.position = {{ + static_cast(position[0]), + static_cast(position[1]), + static_cast(position[2]) + }}; layout.value.value = _fullData[i + _bvColorArrayPos]; layout.value.luminance = _fullData[i + _lumArrayPos]; @@ -1579,7 +1598,11 @@ void RenderableStars::createDataSlice(ColorOption option) { std::array data; } layout = {}; - layout.value.position = { { position[0], position[1], position[2] } }; + layout.value.position = {{ + static_cast(position[0]), + static_cast(position[1]), + static_cast(position[2]) + }}; int index = _otherDataOption.value(); // plus 3 because of the position @@ -1612,6 +1635,8 @@ void RenderableStars::createDataSlice(ColorOption option) { } } } + + setBoundingSphere(maxRadius); } } // namespace openspace diff --git a/modules/touch/src/directinputsolver.cpp b/modules/touch/src/directinputsolver.cpp index 5f19cb5d9f..7a0ea127ae 100644 --- a/modules/touch/src/directinputsolver.cpp +++ b/modules/touch/src/directinputsolver.cpp @@ -146,7 +146,7 @@ void gradient(double* g, double* par, int x, void* fdata, LMstat* lmstat) { FunctionData* ptr = reinterpret_cast(fdata); double f0 = distToMinimize(par, x, fdata, lmstat); // scale value to find minimum step size h, dependant on planet size - double scale = log10(ptr->node->boundingSphere()); + double scale = log10(ptr->node->interactionSphere()); std::vector dPar(ptr->nDOF, 0.0); dPar.assign(par, par + ptr->nDOF); diff --git a/modules/touch/src/touchinteraction.cpp b/modules/touch/src/touchinteraction.cpp index 9eededbcbf..cae7df51d4 100644 --- a/modules/touch/src/touchinteraction.cpp +++ b/modules/touch/src/touchinteraction.cpp @@ -507,15 +507,15 @@ void TouchInteraction::findSelectedNode(const std::vector& lis size_t id = inputHolder.fingerId(); for (SceneGraphNode* node : selectableNodes) { - double boundingSphereSquared = static_cast(node->boundingSphere()) * - static_cast(node->boundingSphere()); + double interactionSphereSquared = + node->interactionSphere() * node->interactionSphere(); glm::dvec3 camToSelectable = node->worldPosition() - camPos; double intersectionDist = 0.0; const bool intersected = glm::intersectRaySphere( camPos, raytrace, node->worldPosition(), - boundingSphereSquared, + interactionSphereSquared, intersectionDist ); if (intersected) { @@ -921,7 +921,7 @@ double TouchInteraction::computeTapZoomDistance(double zoomGain) { global::navigationHandler->orbitalNavigator().anchorNode()->worldPosition() ); - dist -= anchor->boundingSphere(); + dist -= anchor->interactionSphere(); double newVelocity = dist * _tapZoomFactor; newVelocity *= std::max(_touchScreenSize.value() * 0.1, 1.0); @@ -962,9 +962,9 @@ void TouchInteraction::step(double dt, bool directTouch) { dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion(); - const double boundingSphere = anchor->boundingSphere(); - const double distance = std::max(length(centerToCamera) - boundingSphere, 0.0); - _currentRadius = boundingSphere / + const double interactionSphere = anchor->interactionSphere(); + const double distance = std::max(length(centerToCamera) - interactionSphere, 0.0); + _currentRadius = interactionSphere / std::max(distance * _projectionScaleFactor, 1.0); { @@ -1010,7 +1010,7 @@ void TouchInteraction::step(double dt, bool directTouch) { // This is a rough estimate of the node surface // If nobody has set another zoom in limit, use this as default zoom in bounds - double zoomInBounds = boundingSphere * _zoomBoundarySphereMultiplier; + double zoomInBounds = interactionSphere * _zoomBoundarySphereMultiplier; bool isZoomInLimitSet = (_zoomInLimit.value() >= 0.0); if (isZoomInLimitSet && _zoomInLimit.value() < zoomInBounds) { @@ -1049,7 +1049,7 @@ void TouchInteraction::step(double dt, bool directTouch) { double zoomVelocity = _vel.zoom; if (!directTouch) { const double distanceFromSurface = - length(currentPosDistance) - anchor->boundingSphere(); + length(currentPosDistance) - anchor->interactionSphere(); if (distanceFromSurface > 0.1) { const double ratioOfDistanceToNodeVsSurf = length(currentPosDistance) / distanceFromSurface; diff --git a/shaders/core/xyzuvrgba_fs.glsl b/shaders/core/xyzuvrgba_fs.glsl new file mode 100644 index 0000000000..e26b92ca4c --- /dev/null +++ b/shaders/core/xyzuvrgba_fs.glsl @@ -0,0 +1,54 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "fragment.glsl" + +uniform bool hasTexture = false; +uniform bvec2 shouldFlipTexture = bvec2(false, false); +uniform sampler2D tex; +uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0); + +in float depth; +in vec2 out_uv; +in vec4 out_color; + +Fragment getFragment() { + Fragment frag; + + if (hasTexture) { + vec2 uv = out_uv; + if (shouldFlipTexture.x) { + uv.x = 1.0 - uv.x; + } + if (shouldFlipTexture.y) { + uv.y = 1.0 - uv.y; + } + frag.color = out_color * color * texture(tex, uv); + } + else { + frag.color = out_color * color; + } + frag.depth = depth; + return frag; +} diff --git a/shaders/core/xyzuvrgba_vs.glsl b/shaders/core/xyzuvrgba_vs.glsl new file mode 100644 index 0000000000..9605a4c6d3 --- /dev/null +++ b/shaders/core/xyzuvrgba_vs.glsl @@ -0,0 +1,43 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +layout(location = 0) in vec3 in_position; +layout(location = 1) in vec2 in_uv; +layout(location = 2) in vec4 in_color; + +out float depth; +out vec2 out_uv; +out vec4 out_color; + +uniform mat4 proj; + +void main() { + out_uv = in_uv; + out_color = in_color; + vec4 p = proj * vec4(in_position, 1.0); + gl_Position = p; + depth = p.w; +} diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 2eca8e12f4..c04c60f985 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -416,8 +416,6 @@ void OpenSpaceEngine::initializeGL() { glbinding::Binding::initialize(global::windowDelegate->openGLProcedureAddress); //glbinding::Binding::useCurrentContext(); - rendering::helper::initialize(); - LDEBUG("Adding system components"); // Detect and log OpenCL and OpenGL versions and available devices SysCap.addComponent( @@ -427,7 +425,6 @@ void OpenSpaceEngine::initializeGL() { std::make_unique() ); - // @BUG: This will call OpenGL functions, should it should be in the initializeGL LDEBUG("Detecting capabilities"); SysCap.detectCapabilities(); @@ -467,6 +464,8 @@ void OpenSpaceEngine::initializeGL() { } } + rendering::helper::initialize(); + loadFonts(); _loadingScreen = std::make_unique( diff --git a/src/engine/openspaceengine_lua.inl b/src/engine/openspaceengine_lua.inl index d5881b8ada..aa16a79db2 100644 --- a/src/engine/openspaceengine_lua.inl +++ b/src/engine/openspaceengine_lua.inl @@ -266,10 +266,14 @@ int removeTag(lua_State* L) { * Downloads a file from Lua interpreter */ int downloadFile(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addTag"); + int n = ghoul::lua::checkArgumentsAndThrow(L, {2, 3}, "lua::addTag"); const std::string& uri = ghoul::lua::value(L, 1); const std::string& savePath = ghoul::lua::value(L, 2); + bool waitForComplete = false; + if (n == 3) { + waitForComplete = ghoul::lua::value(L, 3); + } lua_settop(L, 0); LINFOC("OpenSpaceEngine", fmt::format("Downloading file from {}", uri)); @@ -281,6 +285,14 @@ int downloadFile(lua_State* L) { DownloadManager::FailOnError::Yes, 5 ); + + if (waitForComplete) { + while (!future->isFinished && future->errorMessage.empty() ) { + //just wait + LTRACEC("OpenSpaceEngine", fmt::format("waiting {}", future->errorMessage)); + } + } + if (!future || !future->isFinished) { return ghoul::lua::luaError( L, diff --git a/src/interaction/orbitalnavigator.cpp b/src/interaction/orbitalnavigator.cpp index 9c6d13a15d..b4815e9cc4 100644 --- a/src/interaction/orbitalnavigator.cpp +++ b/src/interaction/orbitalnavigator.cpp @@ -459,8 +459,8 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { if (_applyLinearFlight) { // Calculate a position handle based on the camera position in world space glm::dvec3 camPosToAnchorPosDiff = prevCameraPosition - anchorPos; - // Use the boundingsphere to get an approximate distance to the node surface - double nodeRadius = static_cast(_anchorNode->boundingSphere()); + // Use the interaction sphere to get an approximate distance to the node surface + double nodeRadius = static_cast(_anchorNode->interactionSphere()); double distFromCameraToFocus = glm::distance(prevCameraPosition, anchorPos) - nodeRadius; diff --git a/src/properties/property.cpp b/src/properties/property.cpp index cdfed64adc..5985da3dc6 100644 --- a/src/properties/property.cpp +++ b/src/properties/property.cpp @@ -23,21 +23,17 @@ ****************************************************************************************/ #include - #include - -#include - -#include - #include +#include +#include +#include namespace { constexpr const char* MetaDataKeyGroup = "Group"; - constexpr const char* MetaDataKeyVisibility = "Visibility"; constexpr const char* MetaDataKeyReadOnly = "isReadOnly"; - - constexpr const char* _metaDataKeyViewPrefix = "view"; + constexpr const char* MetaDataKeyViewOptions = "ViewOptions"; + constexpr const char* MetaDataKeyVisibility = "Visibility"; } // namespace @@ -46,8 +42,8 @@ namespace openspace::properties { Property::OnChangeHandle Property::OnChangeHandleAll = std::numeric_limits::max(); -const char* Property::ViewOptions::Color = "color"; -const char* Property::ViewOptions::LightPosition = "lightPosition"; +const char* Property::ViewOptions::Color = "Color"; +const char* Property::ViewOptions::Logarithmic = "Logarithmic"; const char* Property::IdentifierKey = "Identifier"; const char* Property::NameKey = "Name"; @@ -209,14 +205,14 @@ void Property::setReadOnly(bool state) { void Property::setViewOption(std::string option, bool value) { ghoul::Dictionary d; d.setValue(option, value); - _metaData.setValue(_metaDataKeyViewPrefix, d); + _metaData.setValue(MetaDataKeyViewOptions, d); } bool Property::viewOption(const std::string& option, bool defaultValue) const { - if (!_metaData.hasValue(_metaDataKeyViewPrefix)) { + if (!_metaData.hasValue(MetaDataKeyViewOptions)) { return defaultValue; } - ghoul::Dictionary d = _metaData.value(_metaDataKeyViewPrefix); + ghoul::Dictionary d = _metaData.value(MetaDataKeyViewOptions); if (d.hasKey(option)) { return d.value(option); } @@ -357,18 +353,23 @@ std::string Property::generateMetaDataJsonDescription() const { if (_metaData.hasValue(MetaDataKeyReadOnly)) { isReadOnly = _metaData.value(MetaDataKeyReadOnly); } + std::string isReadOnlyString = (isReadOnly ? "true" : "false"); - std::string gIdent = groupIdentifier(); - std::string gIdentSan = sanitizeString(gIdent); + std::string groupId = groupIdentifier(); + std::string sanitizedGroupId = sanitizeString(groupId); + + std::string viewOptions = "{}"; + if (_metaData.hasValue(MetaDataKeyViewOptions)) { + viewOptions = ghoul::formatJson( + _metaData.value(MetaDataKeyViewOptions) + ); + } std::string result = "{ "; - result += - "\"" + std::string(MetaDataKeyGroup) + "\": \"" + gIdentSan + "\", "; - result += - "\"" + std::string(MetaDataKeyVisibility) + "\": \"" + vis + "\", "; - result += - "\"" + std::string(MetaDataKeyReadOnly) + "\": " + - (isReadOnly ? "true" : "false"); + result += fmt::format("\"{}\": \"{}\",", MetaDataKeyGroup, sanitizedGroupId); + result += fmt::format("\"{}\": \"{}\",", MetaDataKeyVisibility, vis); + result += fmt::format("\"{}\": {},", MetaDataKeyReadOnly, isReadOnlyString); + result += fmt::format("\"{}\": {}", MetaDataKeyViewOptions, viewOptions); result += " }"; return result; } diff --git a/src/rendering/helper.cpp b/src/rendering/helper.cpp index 99787c973c..43fa4fae94 100644 --- a/src/rendering/helper.cpp +++ b/src/rendering/helper.cpp @@ -53,17 +53,20 @@ layout(location = 0) in vec2 in_position; layout(location = 1) in vec2 in_uv; layout(location = 2) in vec4 in_color; +out float depth; out vec2 out_position; out vec2 out_uv; out vec4 out_color; -uniform mat4 ortho; +uniform mat4 proj; void main() { out_position = in_position; out_uv = in_uv; out_color = in_color; - gl_Position = ortho * vec4(in_position, 0.0, 1.0); + vec4 p = proj * vec4(in_position, 0.0, 1.0); + gl_Position = p; + depth = p.w; } )"; @@ -90,11 +93,14 @@ void main() { constexpr const char* XyuvrgbaFragmentCode = R"( #version __CONTEXT__ +#include "fragment.glsl" + uniform bool hasTexture = false; uniform bvec2 shouldFlipTexture = bvec2(false, false); uniform sampler2D tex; uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0); +in float depth; in vec2 out_uv; in vec4 out_color; @@ -119,6 +125,7 @@ void main() { } // namespace +#pragma optimize ("", off) namespace openspace::rendering::helper { namespace detail { @@ -150,7 +157,6 @@ void initialize() { vertexFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); vertexFile.open(xyuvrgbaVertexFile, std::fstream::out); vertexFile << XyuvrgbaVertexCode; - vertexFile.close(); } xyuvrgbaFragmentFile = absPath("${TEMPORARY}/xyuvrgba.frag"); @@ -159,13 +165,17 @@ void initialize() { fragmentFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); fragmentFile.open(xyuvrgbaFragmentFile, std::fstream::out); fragmentFile << XyuvrgbaFragmentCode; - fragmentFile.close(); } shaders.xyuvrgba.program = ghoul::opengl::ProgramObject::Build( - "xyuvrgba", xyuvrgbaVertexFile, xyuvrgbaFragmentFile); - ghoul::opengl::updateUniformLocations(*shaders.xyuvrgba.program, + "xyuvrgba", + xyuvrgbaVertexFile, + xyuvrgbaFragmentFile + ); + ghoul::opengl::updateUniformLocations( + *shaders.xyuvrgba.program, shaders.xyuvrgba.cache, - { "tex", "hasTexture", "shouldFlipTexture", "ortho", "color" }); + { "tex", "hasTexture", "shouldFlipTexture", "proj", "color" } + ); // // Screenfilling shader @@ -176,7 +186,6 @@ void initialize() { vertexFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); vertexFile.open(screenFillingVertexFile, std::fstream::out); vertexFile << ScreenFillingQuadVertexCode; - vertexFile.close(); } screenFillingFragmentFile = absPath("${TEMPORARY}/screenfilling.frag"); @@ -185,14 +194,18 @@ void initialize() { fragmentFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); fragmentFile.open(screenFillingFragmentFile, std::fstream::out); fragmentFile << XyuvrgbaFragmentCode; - fragmentFile.close(); } shaders.screenfilling.program = ghoul::opengl::ProgramObject::Build( - "screenfilling", xyuvrgbaVertexFile, xyuvrgbaFragmentFile); - ghoul::opengl::updateUniformLocations(*shaders.screenfilling.program, + "screenfilling", + xyuvrgbaVertexFile, + xyuvrgbaFragmentFile + ); + ghoul::opengl::updateUniformLocations( + *shaders.screenfilling.program, shaders.screenfilling.cache, - { "tex", "hasTexture", "shouldFlipTexture", "ortho", "color" }); + { "tex", "hasTexture", "shouldFlipTexture", "proj", "color" } + ); // @@ -231,6 +244,45 @@ void initialize() { reinterpret_cast(offsetof(VertexXYUVRGBA, rgba))); glBindVertexArray(0); + // + // Sphere vertex array object + // + std::pair, std::vector> sphereData = createSphere( + 64, glm::vec3(1.f, 1.f, 1.f), glm::vec4(1.f, 1.f, 1.f, 1.f) + ); + + glGenVertexArrays(1, &vertexObjects.sphere.vao); + glGenBuffers(1, &vertexObjects.sphere.vbo); + glGenBuffers(1, &vertexObjects.sphere.ibo); + + glBindVertexArray(vertexObjects.sphere.vao); + glBindBuffer(GL_ARRAY_BUFFER, vertexObjects.sphere.vbo); + glBufferData( + GL_ARRAY_BUFFER, + sphereData.first.size() * sizeof(Vertex), + sphereData.first.data(), + GL_STATIC_DRAW + ); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexObjects.sphere.ibo); + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, + sphereData.second.size() * sizeof(GLushort), + sphereData.second.data(), + GL_STATIC_DRAW + ); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), nullptr); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), + reinterpret_cast(offsetof(Vertex, uv))); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), + reinterpret_cast(offsetof(Vertex, rgba))); + glBindVertexArray(0); + vertexObjects.sphere.nElements = static_cast(sphereData.second.size()); + + // // Empty vertex array objects // @@ -262,6 +314,10 @@ void deinitialize() { glDeleteVertexArrays(1, &vertexObjects.square.vao); glDeleteBuffers(1, &vertexObjects.square.vbo); + glDeleteVertexArrays(1, &vertexObjects.sphere.vao); + glDeleteBuffers(1, &vertexObjects.sphere.vbo); + glDeleteBuffers(1, &vertexObjects.sphere.ibo); + glDeleteVertexArrays(1, &vertexObjects.empty.vao); isInitialized = false; @@ -316,14 +372,14 @@ void renderBox(ghoul::opengl::ProgramObject& program, GLint orthoLocation, } void renderBox(const glm::vec2& position, const glm::vec2& size, const glm::vec4& color, - Anchor anchor) + Anchor anchor) { auto& shdr = shaders.xyuvrgba; shdr.program->activate(); shdr.program->setUniform(shdr.cache.hasTexture, 0); renderBox( *shdr.program, - shdr.cache.ortho, + shdr.cache.proj, shdr.cache.color, position, size, color, @@ -345,7 +401,7 @@ void renderBox(const glm::vec2& position, const glm::vec2& size, const glm::vec4 shdr.program->setUniform(shdr.cache.tex, unit); renderBox( *shdr.program, - shdr.cache.ortho, + shdr.cache.proj, shdr.cache.color, position, size, @@ -388,4 +444,63 @@ std::vector createRing(int nSegments, float radius, glm::vec4 colors) { return vertices; } +std::pair, std::vector> createSphere(int nSegments, + glm::vec3 radii, + glm::vec4 colors) +{ + std::vector vertices; + vertices.reserve(nSegments * nSegments); + for (int i = 0; i <= nSegments; i++) { + for (int j = 0; j <= nSegments; j++) { + const float fi = static_cast(i); + const float fj = static_cast(j); + // inclination angle (north to south) + // 0 -> PI + // azimuth angle (east to west) + const float theta = fi * glm::pi() / nSegments; + + // 0 -> 2*PI + const float phi = fj * glm::pi() * 2.f / nSegments; + + const float x = radii[0] * sin(theta) * cos(phi); + const float y = radii[1] * sin(theta) * sin(phi); + const float z = radii[2] * cos(theta); // Z points towards pole (theta = 0) + + Vertex v; + v.xyz[0] = x; + v.xyz[1] = y; + v.xyz[2] = z; + + const float t1 = fj / nSegments; + const float t2 = 1.f - (fi / nSegments); + + v.uv[0] = t1; + v.uv[1] = t2; + + v.rgba[0] = colors.r; + v.rgba[1] = colors.g; + v.rgba[2] = colors.b; + v.rgba[3] = colors.a; + + vertices.push_back(v); + } + } + + std::vector indices; + indices.reserve(vertices.size() * 3); + for (int i = 1; i <= nSegments; i++) { + for (int j = 0; j < nSegments; j++) { + const int t = nSegments + 1; + indices.push_back(static_cast(t * (i - 1) + j + 0)); + indices.push_back(static_cast(t * (i + 0) + j + 0)); + indices.push_back(static_cast(t * (i + 0) + j + 1)); + indices.push_back(static_cast(t * (i - 1) + j + 0)); + indices.push_back(static_cast(t * (i + 0) + j + 1)); + indices.push_back(static_cast(t * (i - 1) + j + 1)); + } + } + + return { vertices, indices }; +} + } // namespace openspace::rendering::helper diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index ffc5ceef16..e416a01e40 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -58,11 +58,6 @@ namespace { openspace::properties::Property::Visibility::Hidden }; - constexpr openspace::properties::Property::PropertyInfo BoundingSphereInfo = { - "BoundingSphere", - "Bounding Sphere", - "The size of the bounding sphere radius." - }; struct [[codegen::Dictionary(Renderable)]] Parameters { // [[codegen::verbatim(EnabledInfo.description)]] std::optional enabled; @@ -76,9 +71,6 @@ namespace { // [[codegen::verbatim(RenderableTypeInfo.description)]] std::optional type; - - // [[codegen::verbatim(BoundingSphereInfo.description)]] - std::optional boundingSphere; }; #include "renderable_codegen.cpp" } // namespace @@ -120,7 +112,6 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary) : properties::PropertyOwner({ "Renderable" }) , _enabled(EnabledInfo, true) , _opacity(OpacityInfo, 1.f, 0.f, 1.f) - , _boundingSphere(BoundingSphereInfo, 0.f, 0.f, 3e10f) , _renderableType(RenderableTypeInfo, "Renderable") { ZoneScoped @@ -154,9 +145,6 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary) // set type for UI _renderableType = p.type.value_or(_renderableType); addProperty(_renderableType); - - _boundingSphere = p.boundingSphere.value_or(_boundingSphere); - addProperty(_boundingSphere); } void Renderable::initialize() {} @@ -179,12 +167,16 @@ double Renderable::boundingSphere() const { return _boundingSphere; } +double Renderable::interactionSphere() const { + return _interactionSphere; +} + SurfacePositionHandle Renderable::calculateSurfacePositionHandle( const glm::dvec3& targetModelSpace) const { const glm::dvec3 directionFromCenterToTarget = glm::normalize(targetModelSpace); return { - directionFromCenterToTarget * boundingSphere(), + directionFromCenterToTarget * _parent->interactionSphere(), directionFromCenterToTarget, 0.0 }; diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 1bf708bdb6..c3c28cc74e 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -1116,30 +1116,18 @@ void RenderEngine::takeScreenshot() { _latestScreenshotNumber = global::windowDelegate->takeScreenshot(_applyWarping); } -/** - * Get the latest screenshot filename - */ unsigned int RenderEngine::latestScreenshotNumber() const { return _latestScreenshotNumber; } -/** - * Set raycasting uniforms on the program object, and setup raycasting. - */ void RenderEngine::preRaycast(ghoul::opengl::ProgramObject& programObject) { _renderer->preRaycast(programObject); } -/** - * Tear down raycasting for the specified program object. - */ void RenderEngine::postRaycast(ghoul::opengl::ProgramObject& programObject) { _renderer->postRaycast(programObject); } -/** - * Set renderer - */ void RenderEngine::setRenderer(std::unique_ptr renderer) { ZoneScoped diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 0f3b760444..2a44f4a5bd 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -31,12 +31,15 @@ #include #include #include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -89,11 +92,23 @@ namespace { constexpr openspace::properties::Property::PropertyInfo BoundingSphereInfo = { "BoundingSphere", "Bounding Sphere", - "The bounding sphere of the scene graph node. This can be the " - "bounding sphere of an attached renderable or directly specified to the node. " - "If there is a boundingsphere on both the renderable and the node, the largest " - "number will be picked.", - openspace::properties::Property::Visibility::Hidden + "The bounding sphere of the scene graph node meaning that everything that this " + "scene graph node renders must be contained within this sphere. This value is " + "only used as an override to the bounding sphere calculated by the Renderable, " + "if present. If this value is -1, the Renderable's computed bounding sphere is " + "used", + openspace::properties::Property::Visibility::Developer + }; + + constexpr openspace::properties::Property::PropertyInfo InteractionSphereInfo = { + "InteractionSphere", + "Interaction Sphere", + "The minimum radius that the camera is allowed to get close to this scene graph " + "node. This value is " + "only used as an override to the bounding sphere calculated by the Renderable, " + "if present. If this value is -1, the Renderable's computed interaction sphere " + "is used", + openspace::properties::Property::Visibility::Developer }; constexpr openspace::properties::Property::PropertyInfo GuiPathInfo = { @@ -128,6 +143,14 @@ namespace { openspace::properties::Property::Visibility::Hidden }; + constexpr openspace::properties::Property::PropertyInfo ShowDebugSphereInfo = { + "ShowDebugSphere", + "Show Debug Sphere", + "If enabled the bounding sphere of this scene graph node is rendered as a debug " + "method", + openspace::properties::Property::Visibility::Developer + }; + struct [[codegen::Dictionary(SceneGraphNode)]] Parameters { // The identifier of this scenegraph node. This name must be unique among all // scene graph nodes that are loaded in a specific scene. If a duplicate is @@ -156,6 +179,10 @@ namespace { // sphere needs to be overwritten for some reason std::optional boundingSphere; + // A hard-coded radius for limiting the interaction radius, meaning the minimal + // distance that the camera can approach this scene graph node + std::optional interactionSphere; + struct Transform { // This node describes a translation that is applied to the scenegraph node // and all its children. Depending on the 'Type' of the translation, this can @@ -258,10 +285,8 @@ ghoul::mm_unique_ptr SceneGraphNode::createFromDictionary( } } - if (p.boundingSphere.has_value()) { - result->_boundingSphere = *p.boundingSphere; - result->_boundingSphere.setVisibility(properties::Property::Visibility::All); - } + result->_overrideBoundingSphere = p.boundingSphere; + result->_overrideInteractionSphere = p.interactionSphere; if (p.transform.has_value()) { if (p.transform->translation.has_value()) { @@ -345,23 +370,11 @@ ghoul::mm_unique_ptr SceneGraphNode::createFromDictionary( if (p.renderable.has_value()) { result->_renderable = Renderable::createFromDictionary(*p.renderable); ghoul_assert(result->_renderable, "Failed to create Renderable"); + result->_renderable->_parent = result.get(); result->addPropertySubOwner(result->_renderable.get()); LDEBUG(fmt::format( "Successfully created renderable for '{}'", result->identifier() )); - - // If the renderable child has a larger bounding sphere, we allow it to override - if (result->_renderable->boundingSphere() > result->_boundingSphere) { - result->_boundingSphere = result->_renderable->boundingSphere(); - - if (p.boundingSphere.has_value()) { - LWARNING(fmt::format( - "The specified property 'BoundingSphere' for '{}' was overwritten " - "by a child renderable", - result->_identifier - )); - } - } } if (p.tag.has_value()) { @@ -392,6 +405,8 @@ documentation::Documentation SceneGraphNode::Documentation() { return doc; } +ghoul::opengl::ProgramObject* SceneGraphNode::_debugSphereProgram = nullptr; + SceneGraphNode::SceneGraphNode() : properties::PropertyOwner({ "" }) , _guiHidden(GuiHiddenInfo) @@ -409,13 +424,15 @@ SceneGraphNode::SceneGraphNode() global::memoryManager->PersistentMemory.alloc() ) } - , _boundingSphere(BoundingSphereInfo, 0.0) + , _boundingSphere(BoundingSphereInfo, -1.0, -1.0, 1e12) + , _interactionSphere(InteractionSphereInfo, -1.0, -1.0, -1.0, 1e12) , _computeScreenSpaceValues(ComputeScreenSpaceInfo, false) , _screenSpacePosition(ScreenSpacePositionInfo, glm::ivec2(-1, -1)) , _screenVisibility(ScreenVisibilityInfo, false) , _distFromCamToNode(DistanceFromCamToNodeInfo, -1.0) , _screenSizeRadius(ScreenSizeRadiusInfo, 0) , _visibilityDistance(VisibilityDistanceInfo, 6e10f) + , _showDebugSphere(ShowDebugSphereInfo, false) { addProperty(_computeScreenSpaceValues); addProperty(_screenSpacePosition); @@ -423,7 +440,25 @@ SceneGraphNode::SceneGraphNode() addProperty(_distFromCamToNode); addProperty(_screenSizeRadius); addProperty(_visibilityDistance); + _boundingSphere.onChange([this]() { + if (_boundingSphere >= 0.0) { + _overrideBoundingSphere = _boundingSphere; + } + else { + _overrideBoundingSphere = std::nullopt; + } + }); addProperty(_boundingSphere); + _interactionSphere.onChange([this]() { + if (_interactionSphere >= 0.0) { + _overrideInteractionSphere = _interactionSphere; + } + else { + _overrideInteractionSphere = std::nullopt; + } + }); + addProperty(_interactionSphere); + addProperty(_showDebugSphere); } SceneGraphNode::~SceneGraphNode() {} // NOLINT @@ -461,6 +496,25 @@ void SceneGraphNode::initializeGL() { if (_renderable) { _renderable->initializeGL(); } + + // The first one to get here will create program shared between all scene graph nodes + if (_debugSphereProgram == nullptr) { + std::unique_ptr shader = + global::renderEngine->buildRenderProgram( + "DebugSphere", + absPath("${SHADERS}/core/xyzuvrgba_vs.glsl"), + absPath("${SHADERS}/core/xyzuvrgba_fs.glsl") + ); + // Since we are only going to create a single of these shaders for the lifetime of + // the program, we are not bothering with freeing it as the overhead of detecting + // when the last scenegraph node will be destroyed would be a bit too much for the + // benefit that we would gain from it + _debugSphereProgram = shader.release(); + _debugSphereProgram->setIgnoreUniformLocationError( + ghoul::opengl::ProgramObject::IgnoreError::Yes + ); + } + _state = State::GLInitialized; LDEBUG(fmt::format("Finished initializating GL: {}", identifier())); @@ -598,6 +652,59 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) { computeScreenSpaceData(newData); } } + + if (_showDebugSphere) { + if (const double bs = boundingSphere(); bs > 0.0) { + renderDebugSphere(data.camera, bs, glm::vec4(0.5f, 0.15f, 0.5f, 0.75f)); + } + + if (const double is = interactionSphere(); is > 0.0) { + renderDebugSphere(data.camera, is, glm::vec4(0.15f, 0.35f, 0.85f, 0.75f)); + } + } +} + +void SceneGraphNode::renderDebugSphere(const Camera& camera, double size, glm::vec4 color) +{ + glm::dvec3 scaleVec = _worldScaleCached * size; + glm::dmat4 modelTransform = + glm::translate(glm::dmat4(1.0), _worldPositionCached) * + glm::dmat4(_worldRotationCached) * + glm::scale(glm::dmat4(1.0), scaleVec); + + glm::mat4 modelViewProjection = camera.projectionMatrix() * + glm::mat4(camera.combinedViewMatrix() * modelTransform); + + _debugSphereProgram->activate(); + _debugSphereProgram->setUniform("hasTexture", 0); + _debugSphereProgram->setUniform("proj", modelViewProjection); + _debugSphereProgram->setUniform("color", color); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + + glBindVertexArray(rendering::helper::vertexObjects.sphere.vao); + glDrawElements( + GL_TRIANGLES, + rendering::helper::vertexObjects.sphere.nElements, + GL_UNSIGNED_SHORT, + nullptr + ); + + glLineWidth(2.0); + _debugSphereProgram->setUniform("color", glm::vec4(1.f, 1.f, 1.f, 1.f)); + glDrawElements( + GL_LINES, + rendering::helper::vertexObjects.sphere.nElements, + GL_UNSIGNED_SHORT, + nullptr + ); + + glBindVertexArray(0); + + _debugSphereProgram->deactivate(); } void SceneGraphNode::setParent(SceneGraphNode& parent) { @@ -955,7 +1062,29 @@ std::vector SceneGraphNode::children() const { } double SceneGraphNode::boundingSphere() const { - return _boundingSphere; + if (_overrideBoundingSphere.has_value()) { + return glm::compMax(scale() * *_overrideBoundingSphere); + } + + if (_renderable) { + return glm::compMax(scale() * _renderable->boundingSphere()); + } + else { + return 0.0; + } +} + +double SceneGraphNode::interactionSphere() const { + if (_overrideInteractionSphere.has_value()) { + return glm::compMax(scale() * *_overrideInteractionSphere); + } + + if (_renderable) { + return glm::compMax(scale() * _renderable->interactionSphere()); + } + else { + return 0.0; + } } const Renderable* SceneGraphNode::renderable() const {