diff --git a/include/openspace/rendering/dashboard.h b/include/openspace/rendering/dashboard.h index 85f1347319..478df62b8b 100644 --- a/include/openspace/rendering/dashboard.h +++ b/include/openspace/rendering/dashboard.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -43,6 +44,14 @@ public: Dashboard(); virtual ~Dashboard() override = default; + /** + * Renders all of the items of this Dashboard at the provided \p penPosition. The + * position is provided in pixels with the top-left corner being located at (0,0). The + * rendering of the DashboardItems will update the \p penPosition according to where + * the next item should be placed. + * + * \param penPosition The location at which we want to render the dashboard items + */ void render(glm::vec2& penPosition); void addDashboardItem(std::unique_ptr item); @@ -63,8 +72,10 @@ public: private: properties::BoolProperty _isEnabled; properties::IVec2Property _startPositionOffset; + properties::IntProperty _refreshRate; std::vector> _items; + std::chrono::steady_clock::time_point _lastRefresh; }; } // openspace diff --git a/include/openspace/rendering/dashboarditem.h b/include/openspace/rendering/dashboarditem.h index cfa71235b5..bb50dc34d6 100644 --- a/include/openspace/rendering/dashboarditem.h +++ b/include/openspace/rendering/dashboarditem.h @@ -45,6 +45,18 @@ public: explicit DashboardItem(const ghoul::Dictionary& dictionary); bool isEnabled() const; + virtual void update() = 0; + + /** + * Renders this DashboardItem at the provided \p penPosition. The position indicates + * where this DashboardItem should render itself and is provided in pixel-coordinates + * with the top-left corner of the screen being at (0,0). Each derived subclass shall + * update the \p penPosition according to the items that it should render. If, for + * example, a single line of text is rendered, the \p penPosition shall be updated by + * one line's worth of vertical separation. + * + * \p penPosition The position at which this DashboardItem should be rendered + */ virtual void render(glm::vec2& penPosition) = 0; virtual glm::vec2 size() const = 0; diff --git a/include/openspace/rendering/dashboardtextitem.h b/include/openspace/rendering/dashboardtextitem.h index e0fdda6b45..5c0192d0cb 100644 --- a/include/openspace/rendering/dashboardtextitem.h +++ b/include/openspace/rendering/dashboardtextitem.h @@ -42,6 +42,8 @@ public: explicit DashboardTextItem(const ghoul::Dictionary& dictionary, float fontSize = 10.f, const std::string& fontName = "Mono"); + void render(glm::vec2& penPosition) override; + static documentation::Documentation Documentation(); protected: @@ -49,6 +51,7 @@ protected: properties::FloatProperty _fontSize; std::shared_ptr _font; + std::string _buffer; }; } // openspace diff --git a/modules/base/dashboard/dashboarditemangle.cpp b/modules/base/dashboard/dashboarditemangle.cpp index 1d87375a91..e67dbe6146 100644 --- a/modules/base/dashboard/dashboarditemangle.cpp +++ b/modules/base/dashboard/dashboarditemangle.cpp @@ -248,10 +248,10 @@ DashboardItemAngle::DashboardItemAngle(const ghoul::Dictionary& dictionary) } addProperty(_destination.nodeName); - _buffer.resize(128); + _localBuffer.resize(128); } -void DashboardItemAngle::render(glm::vec2& penPosition) { +void DashboardItemAngle::update() { ZoneScoped; std::pair sourceInfo = positionAndLabel(_source); @@ -261,19 +261,14 @@ void DashboardItemAngle::render(glm::vec2& penPosition) { const glm::dvec3 a = referenceInfo.first - sourceInfo.first; const glm::dvec3 b = destinationInfo.first - sourceInfo.first; - std::fill(_buffer.begin(), _buffer.end(), char(0)); + std::fill(_localBuffer.begin(), _localBuffer.end(), char(0)); if (glm::length(a) == 0.0 || glm::length(b) == 0) { char* end = std::format_to( - _buffer.data(), + _localBuffer.data(), "Could not compute angle at {} between {} and {}", sourceInfo.second, destinationInfo.second, referenceInfo.second ); - const std::string_view text = std::string_view( - _buffer.data(), - end - _buffer.data() - ); - penPosition.y -= _font->height(); - RenderFont(*_font, penPosition, text); + _buffer = std::string(_localBuffer.data(), end - _localBuffer.data()); } else { const double angle = glm::degrees( @@ -281,15 +276,11 @@ void DashboardItemAngle::render(glm::vec2& penPosition) { ); char* end = std::format_to( - _buffer.data(), + _localBuffer.data(), "Angle at {} between {} and {}: {} degrees", sourceInfo.second, destinationInfo.second, referenceInfo.second, angle ); - const std::string_view text = std::string_view( - _buffer.data(), end - _buffer.data() - ); - penPosition.y -= _font->height(); - RenderFont(*_font, penPosition, text); + _buffer = std::string(_localBuffer.data(), end - _localBuffer.data()); } } diff --git a/modules/base/dashboard/dashboarditemangle.h b/modules/base/dashboard/dashboarditemangle.h index f2f6f823d3..533d30825d 100644 --- a/modules/base/dashboard/dashboarditemangle.h +++ b/modules/base/dashboard/dashboarditemangle.h @@ -42,7 +42,7 @@ public: explicit DashboardItemAngle(const ghoul::Dictionary& dictionary); ~DashboardItemAngle() override = default; - void render(glm::vec2& penPosition) override; + void update() override; glm::vec2 size() const override; @@ -61,7 +61,7 @@ private: Component _reference; Component _destination; - std::vector _buffer; + std::vector _localBuffer; }; } // namespace openspace diff --git a/modules/base/dashboard/dashboarditemdate.cpp b/modules/base/dashboard/dashboarditemdate.cpp index cd8bb38736..cbef64632f 100644 --- a/modules/base/dashboard/dashboarditemdate.cpp +++ b/modules/base/dashboard/dashboarditemdate.cpp @@ -84,7 +84,7 @@ DashboardItemDate::DashboardItemDate(const ghoul::Dictionary& dictionary) addProperty(_timeFormat); } -void DashboardItemDate::render(glm::vec2& penPosition) { +void DashboardItemDate::update() { ZoneScoped; std::string time = SpiceManager::ref().dateFromEphemerisTime( @@ -93,13 +93,8 @@ void DashboardItemDate::render(glm::vec2& penPosition) { ); try { - penPosition.y -= _font->height(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_formatString.value(), std::make_format_args(time)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_formatString.value(), std::make_format_args(time)); } catch (const std::format_error&) { LERRORC("DashboardItemDate", "Illegal format string"); diff --git a/modules/base/dashboard/dashboarditemdate.h b/modules/base/dashboard/dashboarditemdate.h index bdccb30321..da88893560 100644 --- a/modules/base/dashboard/dashboarditemdate.h +++ b/modules/base/dashboard/dashboarditemdate.h @@ -38,7 +38,7 @@ public: explicit DashboardItemDate(const ghoul::Dictionary& dictionary); ~DashboardItemDate() override = default; - void render(glm::vec2& penPosition) override; + void update() override; glm::vec2 size() const override; diff --git a/modules/base/dashboard/dashboarditemdistance.cpp b/modules/base/dashboard/dashboarditemdistance.cpp index 6fb3205e37..5d79dd39a7 100644 --- a/modules/base/dashboard/dashboarditemdistance.cpp +++ b/modules/base/dashboard/dashboarditemdistance.cpp @@ -260,7 +260,7 @@ DashboardItemDistance::DashboardItemDistance(const ghoul::Dictionary& dictionary _formatString = p.formatString.value_or(_formatString); addProperty(_formatString); - _buffer.resize(256); + _localBuffer.resize(256); } std::pair DashboardItemDistance::positionAndLabel( @@ -321,7 +321,7 @@ std::pair DashboardItemDistance::positionAndLabel( } } -void DashboardItemDistance::render(glm::vec2& penPosition) { +void DashboardItemDistance::update() { ZoneScoped; std::pair sourceInfo = positionAndLabel( @@ -344,11 +344,11 @@ void DashboardItemDistance::render(glm::vec2& penPosition) { dist = std::pair(convertedD, nameForDistanceUnit(unit, convertedD != 1.0)); } - std::fill(_buffer.begin(), _buffer.end(), char(0)); + std::fill(_localBuffer.begin(), _localBuffer.end(), char(0)); try { // @CPP26(abock): This can be replaced with std::runtime_format char* end = std::vformat_to( - _buffer.data(), + _localBuffer.data(), _formatString.value(), std::make_format_args( sourceInfo.second, @@ -358,9 +358,7 @@ void DashboardItemDistance::render(glm::vec2& penPosition) { ) ); - penPosition.y -= _font->height(); - const std::string_view t = std::string_view(_buffer.data(), end - _buffer.data()); - RenderFont(*_font, penPosition, t); + _buffer = std::string(_localBuffer.data(), end - _localBuffer.data()); } catch (const std::format_error&) { LERRORC("DashboardItemDate", "Illegal format string"); diff --git a/modules/base/dashboard/dashboarditemdistance.h b/modules/base/dashboard/dashboarditemdistance.h index 7b79e84a2c..6992ead190 100644 --- a/modules/base/dashboard/dashboarditemdistance.h +++ b/modules/base/dashboard/dashboarditemdistance.h @@ -43,7 +43,7 @@ public: explicit DashboardItemDistance(const ghoul::Dictionary& dictionary); ~DashboardItemDistance() override = default; - void render(glm::vec2& penPosition) override; + void update() override; glm::vec2 size() const override; @@ -66,7 +66,7 @@ private: Component _source; Component _destination; - std::vector _buffer; + std::vector _localBuffer; }; } // namespace openspace diff --git a/modules/base/dashboard/dashboarditemelapsedtime.cpp b/modules/base/dashboard/dashboarditemelapsedtime.cpp index bd0dda43b5..4426fb6363 100644 --- a/modules/base/dashboard/dashboarditemelapsedtime.cpp +++ b/modules/base/dashboard/dashboarditemelapsedtime.cpp @@ -136,13 +136,11 @@ DashboardItemElapsedTime::DashboardItemElapsedTime(const ghoul::Dictionary& dict addProperty(_lowestTimeUnit); } -void DashboardItemElapsedTime::render(glm::vec2& penPosition) { +void DashboardItemElapsedTime::update() { ZoneScoped; const double delta = global::timeManager->time().j2000Seconds() - _referenceJ2000; - penPosition.y -= _font->height(); - if (_simplifyTime) { using namespace std::chrono; @@ -161,21 +159,13 @@ void DashboardItemElapsedTime::render(glm::vec2& penPosition) { // Remove the " " at the end time = time.substr(0, time.size() - 1); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_formatString.value(), std::make_format_args(time)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_formatString.value(), std::make_format_args(time)); } else { std::string time = std::format("{} s", delta); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_formatString.value(), std::make_format_args(time)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_formatString.value(), std::make_format_args(time)); } } diff --git a/modules/base/dashboard/dashboarditemelapsedtime.h b/modules/base/dashboard/dashboarditemelapsedtime.h index 5a403b9907..8918061294 100644 --- a/modules/base/dashboard/dashboarditemelapsedtime.h +++ b/modules/base/dashboard/dashboarditemelapsedtime.h @@ -40,7 +40,7 @@ public: explicit DashboardItemElapsedTime(const ghoul::Dictionary& dictionary); ~DashboardItemElapsedTime() override = default; - void render(glm::vec2& penPosition) override; + void update() override; glm::vec2 size() const override; diff --git a/modules/base/dashboard/dashboarditemframerate.cpp b/modules/base/dashboard/dashboarditemframerate.cpp index caf65ccf54..4971cb1e8e 100644 --- a/modules/base/dashboard/dashboarditemframerate.cpp +++ b/modules/base/dashboard/dashboarditemframerate.cpp @@ -200,11 +200,10 @@ DashboardItemFramerate::DashboardItemFramerate(const ghoul::Dictionary& dictiona _shouldClearCache = true; }); addProperty(_clearCache); - - _buffer.resize(128); + _localBuffer.resize(128); } -void DashboardItemFramerate::render(glm::vec2& penPosition) { +void DashboardItemFramerate::update() { ZoneScoped; if (_shouldClearCache) { @@ -224,28 +223,21 @@ void DashboardItemFramerate::render(glm::vec2& penPosition) { const FrametimeType frametimeType = FrametimeType(_frametimeType.value()); - std::fill(_buffer.begin(), _buffer.end(), char(0)); + std::fill(_localBuffer.begin(), _localBuffer.end(), char(0)); char* end = format( - _buffer, + _localBuffer, frametimeType, _minDeltaTimeCache, _maxDeltaTimeCache ); - const std::string_view text = std::string_view(_buffer.data(), end - _buffer.data()); - - const int nLines = text.empty() ? - 0 : - static_cast((std::count(text.begin(), text.end(), '\n') + 1)); - - penPosition.y -= _font->height() * static_cast(nLines); - RenderFont(*_font, penPosition, text); + _buffer = std::string(_localBuffer.data(), end - _localBuffer.data()); } glm::vec2 DashboardItemFramerate::size() const { ZoneScoped; const FrametimeType t = FrametimeType(_frametimeType.value()); - char* end = format(_buffer, t, _minDeltaTimeCache, _maxDeltaTimeCache); + char* end = format(_localBuffer, t, _minDeltaTimeCache, _maxDeltaTimeCache); const std::string_view res = std::string_view(_buffer.data(), end - _buffer.data()); if (res.empty()) { diff --git a/modules/base/dashboard/dashboarditemframerate.h b/modules/base/dashboard/dashboarditemframerate.h index 96fe7ef51b..4ac1c393e2 100644 --- a/modules/base/dashboard/dashboarditemframerate.h +++ b/modules/base/dashboard/dashboarditemframerate.h @@ -40,8 +40,9 @@ class DashboardItemFramerate : public DashboardTextItem { public: explicit DashboardItemFramerate(const ghoul::Dictionary& dictionary); - void render(glm::vec2& penPosition) override; + void update() override; glm::vec2 size() const override; + static documentation::Documentation Documentation(); private: @@ -51,7 +52,7 @@ private: double _minDeltaTimeCache = 1.0; double _maxDeltaTimeCache = -1.0; bool _shouldClearCache = true; - mutable std::vector _buffer; + mutable std::vector _localBuffer; }; } // openspace diff --git a/modules/base/dashboard/dashboarditeminputstate.cpp b/modules/base/dashboard/dashboarditeminputstate.cpp index c2db12044c..f723c51e4e 100644 --- a/modules/base/dashboard/dashboarditeminputstate.cpp +++ b/modules/base/dashboard/dashboarditeminputstate.cpp @@ -123,7 +123,7 @@ DashboardItemInputState::DashboardItemInputState(const ghoul::Dictionary& dictio addProperty(_showJoystick); } -void DashboardItemInputState::render(glm::vec2& penPosition) { +void DashboardItemInputState::update() { ZoneScoped; std::vector text; @@ -167,9 +167,7 @@ void DashboardItemInputState::render(glm::vec2& penPosition) { } if (!text.empty()) { - penPosition.y -= _font->height(); - const std::string t = ghoul::join(std::move(text), "\n"); - RenderFont(*_font, penPosition, t); + _buffer = ghoul::join(std::move(text), "\n"); } } diff --git a/modules/base/dashboard/dashboarditeminputstate.h b/modules/base/dashboard/dashboarditeminputstate.h index 3626983407..0d490a3b0c 100644 --- a/modules/base/dashboard/dashboarditeminputstate.h +++ b/modules/base/dashboard/dashboarditeminputstate.h @@ -39,7 +39,7 @@ public: explicit DashboardItemInputState(const ghoul::Dictionary& dictionary); ~DashboardItemInputState() override = default; - void render(glm::vec2& penPosition) override; + void update() override; glm::vec2 size() const override; diff --git a/modules/base/dashboard/dashboarditemmission.cpp b/modules/base/dashboard/dashboarditemmission.cpp index ea43faf857..7e3e951d00 100644 --- a/modules/base/dashboard/dashboarditemmission.cpp +++ b/modules/base/dashboard/dashboarditemmission.cpp @@ -66,6 +66,8 @@ DashboardItemMission::DashboardItemMission(const ghoul::Dictionary& dictionary) : DashboardTextItem(dictionary, 15.f) {} +void DashboardItemMission::update() {} + void DashboardItemMission::render(glm::vec2& penPosition) { ZoneScoped; diff --git a/modules/base/dashboard/dashboarditemmission.h b/modules/base/dashboard/dashboarditemmission.h index e898f6dfd2..b57b521488 100644 --- a/modules/base/dashboard/dashboarditemmission.h +++ b/modules/base/dashboard/dashboarditemmission.h @@ -36,6 +36,7 @@ public: explicit DashboardItemMission(const ghoul::Dictionary& dictionary); ~DashboardItemMission() override = default; + void update() override; void render(glm::vec2& penPosition) override; glm::vec2 size() const override; diff --git a/modules/base/dashboard/dashboarditemparallelconnection.cpp b/modules/base/dashboard/dashboarditemparallelconnection.cpp index 4de61ad8d8..7c088495cb 100644 --- a/modules/base/dashboard/dashboarditemparallelconnection.cpp +++ b/modules/base/dashboard/dashboarditemparallelconnection.cpp @@ -32,8 +32,6 @@ #include #include #include -#include -#include #include namespace openspace { @@ -50,7 +48,7 @@ DashboardItemParallelConnection::DashboardItemParallelConnection( : DashboardTextItem(dictionary) {} -void DashboardItemParallelConnection::render(glm::vec2& penPosition) { +void DashboardItemParallelConnection::update() { ZoneScoped; const ParallelConnection::Status status = global::parallelPeer->status(); @@ -59,50 +57,44 @@ void DashboardItemParallelConnection::render(glm::vec2& penPosition) { int nLines = 1; - std::string connectionInfo; int nClients = static_cast(nConnections); if (status == ParallelConnection::Status::Host) { nClients--; constexpr std::string_view Singular = "Hosting session with {} client"; constexpr std::string_view Plural = "Hosting session with {} clients"; - connectionInfo = + _buffer = (nClients == 1) ? std::format(Singular, nClients) : std::format(Plural, nClients); } else if (status == ParallelConnection::Status::ClientWithHost) { nClients--; - connectionInfo = "Session hosted by '" + hostName + "'"; + _buffer = "Session hosted by '" + hostName + "'"; } else if (status == ParallelConnection::Status::ClientWithoutHost) { - connectionInfo = "Host is disconnected"; + _buffer = "Host is disconnected"; } if (status == ParallelConnection::Status::ClientWithHost || status == ParallelConnection::Status::ClientWithoutHost) { - connectionInfo += "\n"; + _buffer += "\n"; if (nClients > 2) { constexpr std::string_view Plural = "You and {} more clients are tuned in"; - connectionInfo += std::format(Plural, nClients - 1); + _buffer += std::format(Plural, nClients - 1); } else if (nClients == 2) { constexpr std::string_view Singular = "You and {} more client are tuned in"; - connectionInfo += std::format(Singular, nClients - 1); + _buffer += std::format(Singular, nClients - 1); } else if (nClients == 1) { - connectionInfo += "You are the only client"; + _buffer += "You are the only client"; } nLines = 2; } - - if (!connectionInfo.empty()) { - penPosition.y -= _font->height() * nLines; - RenderFont(*_font, penPosition, connectionInfo); - } } glm::vec2 DashboardItemParallelConnection::size() const { diff --git a/modules/base/dashboard/dashboarditemparallelconnection.h b/modules/base/dashboard/dashboarditemparallelconnection.h index aba4179322..e8e58714c7 100644 --- a/modules/base/dashboard/dashboarditemparallelconnection.h +++ b/modules/base/dashboard/dashboarditemparallelconnection.h @@ -36,7 +36,7 @@ public: explicit DashboardItemParallelConnection(const ghoul::Dictionary& dictionary); ~DashboardItemParallelConnection() override = default; - void render(glm::vec2& penPosition) override; + void update() override; glm::vec2 size() const override; diff --git a/modules/base/dashboard/dashboarditempropertyvalue.cpp b/modules/base/dashboard/dashboarditempropertyvalue.cpp index f9d7baa9e0..0b09c2bc23 100644 --- a/modules/base/dashboard/dashboarditempropertyvalue.cpp +++ b/modules/base/dashboard/dashboarditempropertyvalue.cpp @@ -107,7 +107,7 @@ DashboardItemPropertyValue::DashboardItemPropertyValue( addProperty(_displayString); } -void DashboardItemPropertyValue::render(glm::vec2& penPosition) { +void DashboardItemPropertyValue::update() { ZoneScoped; if (_propertyIsDirty) { @@ -119,209 +119,136 @@ void DashboardItemPropertyValue::render(glm::vec2& penPosition) { return; } const std::string_view type = _property->className(); - penPosition.y -= _font->height(); if (type == "DoubleProperty") { double value = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(value)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_displayString.value(), std::make_format_args(value)); } else if (type == "FloatProperty") { float value = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(value)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_displayString.value(), std::make_format_args(value)); } else if (type == "IntProperty") { int value = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(value)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_displayString.value(), std::make_format_args(value)); } else if (type == "LongProperty") { long value = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(value)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_displayString.value(), std::make_format_args(value)); } else if (type == "ShortProperty") { short value = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(value)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_displayString.value(), std::make_format_args(value)); } else if (type == "UIntProperty") { unsigned int v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(v)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_displayString.value(), std::make_format_args(v)); } else if (type == "ULongProperty") { unsigned long v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(v)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_displayString.value(), std::make_format_args(v)); } else if (type == "UShortProperty") { unsigned short v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(v)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_displayString.value(), std::make_format_args(v)); } else if (type == "DVec2Property") { glm::dvec2 v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(v.x, v.y)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_displayString.value(), std::make_format_args(v.x, v.y)); } else if (type == "DVec3Property") { glm::dvec3 v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(v.x, v.y, v.z)) + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat( + _displayString.value(), + std::make_format_args(v.x, v.y, v.z) ); } else if (type == "DVec4Property") { glm::dvec4 v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat( - _displayString.value(), - std::make_format_args(v.x, v.y, v.z, v.w) - ) + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat( + _displayString.value(), + std::make_format_args(v.x, v.y, v.z, v.w) ); } else if (type == "IVec2Property") { glm::ivec2 v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(v.x, v.y)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_displayString.value(), std::make_format_args(v.x, v.y)); } else if (type == "IVec3Property") { glm::ivec3 v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(v.x, v.y, v.z)) + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat( + _displayString.value(), + std::make_format_args(v.x, v.y, v.z) ); } else if (type == "IVec4Property") { glm::ivec4 v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat( - _displayString.value(), - std::make_format_args(v.x, v.y, v.z, v.w) - ) + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat( + _displayString.value(), + std::make_format_args(v.x, v.y, v.z, v.w) ); } else if (type == "UVec2Property") { glm::uvec2 v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(v.x, v.y)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_displayString.value(), std::make_format_args(v.x, v.y)); } else if (type == "UVec3Property") { glm::uvec3 v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(v.x, v.y, v.z)) + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat( + _displayString.value(), + std::make_format_args(v.x, v.y, v.z) ); } else if (type == "UVec4Property") { glm::uvec4 v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat( - _displayString.value(), - std::make_format_args(v.x, v.y, v.z, v.w) - ) + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat( + _displayString.value(), + std::make_format_args(v.x, v.y, v.z, v.w) ); } else if (type == "Vec2Property") { glm::vec2 v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(v.x, v.y)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_displayString.value(), std::make_format_args(v.x, v.y)); } else if (type == "Vec3Property") { glm::vec3 v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(v.x, v.y, v.z)) + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat( + _displayString.value(), + std::make_format_args(v.x, v.y, v.z) ); } else if (type == "Vec4Property") { glm::vec4 v = static_cast(_property)->value(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat( - _displayString.value(), - std::make_format_args(v.x, v.y, v.z, v.w) - ) + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat( + _displayString.value(), + std::make_format_args(v.x, v.y, v.z, v.w) ); } else { // Fallback if we don't have a special case above std::string value = _property->stringValue(); - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat(_displayString.value(), std::make_format_args(value)) - ); + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat(_displayString.value(), std::make_format_args(value)); } } diff --git a/modules/base/dashboard/dashboarditempropertyvalue.h b/modules/base/dashboard/dashboarditempropertyvalue.h index eb6d7edfba..9d6a38d54b 100644 --- a/modules/base/dashboard/dashboarditempropertyvalue.h +++ b/modules/base/dashboard/dashboarditempropertyvalue.h @@ -40,7 +40,7 @@ public: DashboardItemPropertyValue(const ghoul::Dictionary& dictionary); ~DashboardItemPropertyValue() override = default; - void render(glm::vec2& penPosition) override; + void update() override; glm::vec2 size() const override; diff --git a/modules/base/dashboard/dashboarditemsimulationincrement.cpp b/modules/base/dashboard/dashboarditemsimulationincrement.cpp index dc788555f9..c2879e07c7 100644 --- a/modules/base/dashboard/dashboarditemsimulationincrement.cpp +++ b/modules/base/dashboard/dashboarditemsimulationincrement.cpp @@ -154,7 +154,7 @@ DashboardItemSimulationIncrement::DashboardItemSimulationIncrement( addProperty(_regularFormat); } -void DashboardItemSimulationIncrement::render(glm::vec2& penPosition) { +void DashboardItemSimulationIncrement::update() { ZoneScoped; const double targetDt = global::timeManager->targetDeltaTime(); @@ -188,35 +188,26 @@ void DashboardItemSimulationIncrement::render(glm::vec2& penPosition) { std::string pauseText = global::timeManager->isPaused() ? " (Paused)" : ""; try { - penPosition.y -= _font->height(); if (targetDt != currentDt && !global::timeManager->isPaused()) { // We are in the middle of a transition - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat( - _transitionFormat.value(), - std::make_format_args( - targetDeltaTime.first, targetDeltaTime.second, - pauseText, - currentDeltaTime.first, currentDeltaTime.second - ) + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat( + _transitionFormat.value(), + std::make_format_args( + targetDeltaTime.first, targetDeltaTime.second, + pauseText, + currentDeltaTime.first, currentDeltaTime.second ) ); } else { - RenderFont( - *_font, - penPosition, - // @CPP26(abock): This can be replaced with std::runtime_format - std::vformat( - _regularFormat.value(), - std::make_format_args( - targetDeltaTime.first, - targetDeltaTime.second, - pauseText - ) + // @CPP26(abock): This can be replaced with std::runtime_format + _buffer = std::vformat( + _regularFormat.value(), + std::make_format_args( + targetDeltaTime.first, + targetDeltaTime.second, + pauseText ) ); } diff --git a/modules/base/dashboard/dashboarditemsimulationincrement.h b/modules/base/dashboard/dashboarditemsimulationincrement.h index d15d62e05e..0131c526eb 100644 --- a/modules/base/dashboard/dashboarditemsimulationincrement.h +++ b/modules/base/dashboard/dashboarditemsimulationincrement.h @@ -40,7 +40,7 @@ public: explicit DashboardItemSimulationIncrement(const ghoul::Dictionary& dictionary); ~DashboardItemSimulationIncrement() override = default; - void render(glm::vec2& penPosition) override; + void update() override; glm::vec2 size() const override; static documentation::Documentation Documentation(); diff --git a/modules/base/dashboard/dashboarditemspacing.cpp b/modules/base/dashboard/dashboarditemspacing.cpp index 344d3c0e12..2a485848e3 100644 --- a/modules/base/dashboard/dashboarditemspacing.cpp +++ b/modules/base/dashboard/dashboarditemspacing.cpp @@ -60,6 +60,8 @@ DashboardItemSpacing::DashboardItemSpacing(const ghoul::Dictionary& dictionary) addProperty(_spacing); } +void DashboardItemSpacing::update() {} + void DashboardItemSpacing::render(glm::vec2& penPosition) { penPosition.y -= _spacing; } diff --git a/modules/base/dashboard/dashboarditemspacing.h b/modules/base/dashboard/dashboarditemspacing.h index 4287e8d2ff..325aea71cc 100644 --- a/modules/base/dashboard/dashboarditemspacing.h +++ b/modules/base/dashboard/dashboarditemspacing.h @@ -38,6 +38,7 @@ public: explicit DashboardItemSpacing(const ghoul::Dictionary& dictionary); ~DashboardItemSpacing() override = default; + void update() override; void render(glm::vec2& penPosition) override; glm::vec2 size() const override; diff --git a/modules/base/dashboard/dashboarditemtext.cpp b/modules/base/dashboard/dashboarditemtext.cpp index 6be4f4c05b..16fccfae00 100644 --- a/modules/base/dashboard/dashboarditemtext.cpp +++ b/modules/base/dashboard/dashboarditemtext.cpp @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include #include @@ -66,11 +64,8 @@ DashboardItemText::DashboardItemText(const ghoul::Dictionary& dictionary) addProperty(_text); } -void DashboardItemText::render(glm::vec2& penPosition) { - ZoneScoped; - - penPosition.y -= _font->height(); - RenderFont(*_font, penPosition, _text.value()); +void DashboardItemText::update() { + _buffer = _text.value(); } glm::vec2 DashboardItemText::size() const { diff --git a/modules/base/dashboard/dashboarditemtext.h b/modules/base/dashboard/dashboarditemtext.h index 5f6646612c..1290e452e3 100644 --- a/modules/base/dashboard/dashboarditemtext.h +++ b/modules/base/dashboard/dashboarditemtext.h @@ -38,7 +38,7 @@ public: explicit DashboardItemText(const ghoul::Dictionary& dictionary); ~DashboardItemText() override = default; - void render(glm::vec2& penPosition) override; + void update() override; glm::vec2 size() const override; diff --git a/modules/base/dashboard/dashboarditemvelocity.cpp b/modules/base/dashboard/dashboarditemvelocity.cpp index f76d2c8076..1f9b777028 100644 --- a/modules/base/dashboard/dashboarditemvelocity.cpp +++ b/modules/base/dashboard/dashboarditemvelocity.cpp @@ -34,8 +34,6 @@ #include #include #include -#include -#include #include #include @@ -109,15 +107,15 @@ DashboardItemVelocity::DashboardItemVelocity(const ghoul::Dictionary& dictionary addProperty(_requestedUnit); } -void DashboardItemVelocity::render(glm::vec2& penPosition) { +void DashboardItemVelocity::update() { ZoneScoped; const glm::dvec3 currentPos = global::renderEngine->scene()->camera()->positionVec3(); const glm::dvec3 dt = currentPos - _prevPosition; + _prevPosition = currentPos; + const double speedPerFrame = glm::length(dt); - const double secondsPerFrame = global::windowDelegate->averageDeltaTime(); - const double speedPerSecond = speedPerFrame / secondsPerFrame; std::pair dist; @@ -130,14 +128,7 @@ void DashboardItemVelocity::render(glm::vec2& penPosition) { dist = std::pair(convertedD, nameForDistanceUnit(unit, convertedD != 1.0)); } - penPosition.y -= _font->height(); - RenderFont( - *_font, - penPosition, - std::format("Camera velocity: {:.4f} {}/s", dist.first, dist.second) - ); - - _prevPosition = currentPos; + _buffer = std::format("Camera velocity: {:.4f} {}/s", dist.first, dist.second); } glm::vec2 DashboardItemVelocity::size() const { diff --git a/modules/base/dashboard/dashboarditemvelocity.h b/modules/base/dashboard/dashboarditemvelocity.h index ef49d45825..afb795e8b3 100644 --- a/modules/base/dashboard/dashboarditemvelocity.h +++ b/modules/base/dashboard/dashboarditemvelocity.h @@ -42,7 +42,7 @@ public: explicit DashboardItemVelocity(const ghoul::Dictionary& dictionary); ~DashboardItemVelocity() override = default; - void render(glm::vec2& penPosition) override; + void update() override; glm::vec2 size() const override; diff --git a/modules/globebrowsing/src/dashboarditemglobelocation.cpp b/modules/globebrowsing/src/dashboarditemglobelocation.cpp index 56abacef48..0bda64d749 100644 --- a/modules/globebrowsing/src/dashboarditemglobelocation.cpp +++ b/modules/globebrowsing/src/dashboarditemglobelocation.cpp @@ -136,11 +136,11 @@ DashboardItemGlobeLocation::DashboardItemGlobeLocation( addProperty(_significantDigits); _font = global::fontManager->font(_fontName, _fontSize); - _buffer.resize(128); + _localBuffer.resize(128); updateFormatString(); } -void DashboardItemGlobeLocation::render(glm::vec2& penPosition) { +void DashboardItemGlobeLocation::update() { ZoneScoped; GlobeBrowsingModule* module = global::moduleEngine->module(); @@ -152,14 +152,14 @@ void DashboardItemGlobeLocation::render(glm::vec2& penPosition) { std::pair dist = simplifyDistance(altitude); - std::fill(_buffer.begin(), _buffer.end(), char(0)); + std::fill(_localBuffer.begin(), _localBuffer.end(), char(0)); char* end = nullptr; switch (_displayFormat.value()) { case static_cast(DisplayFormat::DecimalDegrees): { // @CPP26(abock): This can be replaced with std::runtime_format end = std::vformat_to( - _buffer.data(), + _localBuffer.data(), _formatString, std::make_format_args(lat, lon, dist.first, dist.second) ); @@ -188,7 +188,7 @@ void DashboardItemGlobeLocation::render(glm::vec2& penPosition) { // @CPP26(abock): This can be replaced with std::runtime_format end = std::vformat_to( - _buffer.data(), + _localBuffer.data(), _formatString, std::make_format_args( latDeg, latMin, latSec, isNorth ? "N" : "S", @@ -201,9 +201,7 @@ void DashboardItemGlobeLocation::render(glm::vec2& penPosition) { } } - penPosition.y -= _font->height(); - const std::string_view text = std::string_view(_buffer.data(), end - _buffer.data()); - RenderFont(*_font, penPosition, text); + _buffer = std::string(_localBuffer.data(), end - _localBuffer.data()); } glm::vec2 DashboardItemGlobeLocation::size() const { diff --git a/modules/globebrowsing/src/dashboarditemglobelocation.h b/modules/globebrowsing/src/dashboarditemglobelocation.h index 7cffc3c891..951fd57dee 100644 --- a/modules/globebrowsing/src/dashboarditemglobelocation.h +++ b/modules/globebrowsing/src/dashboarditemglobelocation.h @@ -41,7 +41,7 @@ public: explicit DashboardItemGlobeLocation(const ghoul::Dictionary& dictionary); ~DashboardItemGlobeLocation() override = default; - void render(glm::vec2& penPosition) override; + void update() override; glm::vec2 size() const override; @@ -57,7 +57,7 @@ private: properties::IntProperty _significantDigits; std::string _formatString; - std::vector _buffer; + std::vector _localBuffer; }; } // namespace openspace diff --git a/modules/spacecraftinstruments/dashboard/dashboarditeminstruments.cpp b/modules/spacecraftinstruments/dashboard/dashboarditeminstruments.cpp index da1bebe296..11f9107ea7 100644 --- a/modules/spacecraftinstruments/dashboard/dashboarditeminstruments.cpp +++ b/modules/spacecraftinstruments/dashboard/dashboarditeminstruments.cpp @@ -123,6 +123,8 @@ DashboardItemInstruments::DashboardItemInstruments(const ghoul::Dictionary& dict addProperty(_activeFlash); } +void DashboardItemInstruments::update() {} + void DashboardItemInstruments::render(glm::vec2& penPosition) { ZoneScoped; diff --git a/modules/spacecraftinstruments/dashboard/dashboarditeminstruments.h b/modules/spacecraftinstruments/dashboard/dashboarditeminstruments.h index 0ea94060b8..571250d29c 100644 --- a/modules/spacecraftinstruments/dashboard/dashboarditeminstruments.h +++ b/modules/spacecraftinstruments/dashboard/dashboarditeminstruments.h @@ -38,6 +38,7 @@ public: explicit DashboardItemInstruments(const ghoul::Dictionary& dictionary); ~DashboardItemInstruments() override = default; + void update() override; void render(glm::vec2& penPosition) override; glm::vec2 size() const override; diff --git a/src/rendering/dashboard.cpp b/src/rendering/dashboard.cpp index 61a971615e..147d3fc573 100644 --- a/src/rendering/dashboard.cpp +++ b/src/rendering/dashboard.cpp @@ -49,6 +49,14 @@ namespace { "in x and y-direction on screen.", openspace::properties::Property::Visibility::User }; + + constexpr openspace::properties::Property::PropertyInfo RefreshRateInfo = { + "RefreshRate", + "Refresh Rate (in ms)", + "The number of milliseconds between refreshes of the dashboard items. If the " + "value is 0 the dashboard is refreshed at the same rate as the main rendering.", + openspace::properties::Property::Visibility::AdvancedUser + }; } // namespace namespace openspace { @@ -57,9 +65,12 @@ Dashboard::Dashboard() : properties::PropertyOwner({ "Dashboard" }) , _isEnabled(EnabledInfo, true) , _startPositionOffset(StartPositionOffsetInfo, glm::ivec2(10, -10)) + , _refreshRate(RefreshRateInfo, 0, 0, 1000) + , _lastRefresh(std::chrono::high_resolution_clock::now()) { addProperty(_isEnabled); addProperty(_startPositionOffset); + addProperty(_refreshRate); } void Dashboard::addDashboardItem(std::unique_ptr item) { @@ -137,8 +148,17 @@ void Dashboard::render(glm::vec2& penPosition) { return; } + auto now = std::chrono::steady_clock::now(); + bool needsUpdate = (now - _lastRefresh) > std::chrono::milliseconds(_refreshRate); + if (needsUpdate) { + _lastRefresh = now; + } + for (const std::unique_ptr& item : _items) { if (item->isEnabled()) { + if (needsUpdate) { + item->update(); + } item->render(penPosition); } } diff --git a/src/rendering/dashboardtextitem.cpp b/src/rendering/dashboardtextitem.cpp index d40d872d34..e67624cad0 100644 --- a/src/rendering/dashboardtextitem.cpp +++ b/src/rendering/dashboardtextitem.cpp @@ -27,7 +27,9 @@ #include #include #include +#include #include +#include #include namespace { @@ -85,4 +87,14 @@ DashboardTextItem::DashboardTextItem(const ghoul::Dictionary& dictionary, float _font = global::fontManager->font(_fontName, _fontSize); } +void DashboardTextItem::render(glm::vec2& penPosition) { + if (_buffer.empty()) { + return; + } + + const size_t lines = std::count(_buffer.begin(), _buffer.end(), '\n') + 1; + penPosition.y -= _font->height() * lines; + RenderFont(*_font, penPosition, _buffer); +} + } // namespace openspace