From 8731e0e51ce308cd83cd0e969409ba7a4c1580e8 Mon Sep 17 00:00:00 2001 From: Oliver Behnke <oliver.behnke@aei.mpg.de> Date: Fri, 20 Nov 2020 19:55:03 +0100 Subject: [PATCH] HDPI: refreshed HUD layout and added (retina) scaling support * The layout now scales with the display's pixel density (DPI) * Refreshed the layout to make it more readable * The DPI used to design the reference layout must always be kept in sync with AbstractGraphicsEngine::DESIGN_DPI * Tested on macOS 10.15.7 across all scaling factors --- src/framework/AbstractGraphicsEngine.cpp | 4 +++ src/framework/AbstractGraphicsEngine.h | 8 +++++- src/framework/WindowManager.cpp | 28 ++++++++++++++++-- src/framework/WindowManager.h | 3 ++ src/starsphere/Starsphere.cpp | 14 +++++---- src/starsphere/Starsphere.h | 3 +- src/starsphere/StarsphereRadio.cpp | 36 ++++++++++++------------ src/starsphere/StarsphereRadio.h | 3 +- src/starsphere/StarsphereS5R3.cpp | 25 ++++++++-------- src/starsphere/StarsphereS5R3.h | 12 +++++++- src/starsphere/main.cpp | 2 +- 11 files changed, 95 insertions(+), 43 deletions(-) diff --git a/src/framework/AbstractGraphicsEngine.cpp b/src/framework/AbstractGraphicsEngine.cpp index 2f56439..f8f8cea 100644 --- a/src/framework/AbstractGraphicsEngine.cpp +++ b/src/framework/AbstractGraphicsEngine.cpp @@ -29,6 +29,10 @@ AbstractGraphicsEngine::~AbstractGraphicsEngine() { } +void AbstractGraphicsEngine::initialize(const int width, const int height, const float scale, const Resource *font, const bool recycle) { + m_Scale = scale; +} + void AbstractGraphicsEngine::refreshLocalBOINCInformation() { m_BoincAdapter.refresh(); diff --git a/src/framework/AbstractGraphicsEngine.h b/src/framework/AbstractGraphicsEngine.h index e36ee58..f1a1ab8 100644 --- a/src/framework/AbstractGraphicsEngine.h +++ b/src/framework/AbstractGraphicsEngine.h @@ -26,6 +26,8 @@ #include "BOINCClientAdapter.h" #include "Resource.h" +#define DESIGN_DPI 129 + using namespace std; /** @@ -56,10 +58,11 @@ public: * * \param width The current width of the display surface * \param height The current height of the display surface + * \param scale The scaling factor on HDPI displays * \param font A pointer to a Resource object containing TTF font faces for text rendering * \param recycle This flag indicates whether we initialize (FALSE) or reinitialize (TRUE) the context */ - virtual void initialize(const int width, const int height, const Resource *font, const bool recycle = false) = 0; + virtual void initialize(const int width, const int height, const float scale, const Resource *font, const bool recycle = false); /** * \brief This method is called when the windowing system encounters a window resize event @@ -196,6 +199,9 @@ protected: /// BOINC client adapter instance for information retrieval BOINCClientAdapter m_BoincAdapter; + + /// Window scaling factor (relative to design DPI, see above) + float m_Scale; }; /** diff --git a/src/framework/WindowManager.cpp b/src/framework/WindowManager.cpp index 0a7bfbd..a30be54 100644 --- a/src/framework/WindowManager.cpp +++ b/src/framework/WindowManager.cpp @@ -286,7 +286,7 @@ void WindowManager::eventLoop() // notify our observers (currently exactly one, hence front()) // (windoze needs to be reinitialized instead of just resized, oh well) /// \todo Can we determine the host OS? On X11 a resize() is sufficient! - eventObservers.front()->initialize(m_CurrentWidth, m_CurrentHeight, 0, true); + eventObservers.front()->initialize(m_CurrentWidth, m_CurrentHeight, getDisplayScalingFactor(), 0, true); } else if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { m_WindowedWidth = event.window.data1; @@ -298,7 +298,7 @@ void WindowManager::eventLoop() // notify our observers (currently exactly one, hence front()) // (windoze needs to be reinitialized instead of just resized, oh well) /// \todo Can we determine the host OS? On X11 a resize() is sufficient! - eventObservers.front()->initialize(m_CurrentWidth, m_CurrentHeight, 0, true); + eventObservers.front()->initialize(m_CurrentWidth, m_CurrentHeight, getDisplayScalingFactor(), 0, true); } else if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)) { @@ -474,10 +474,32 @@ void WindowManager::toggleFullscreen() // notify our observers (currently exactly one, hence front()) // (windoze needs to be reinitialized instead of just resized, oh well) /// \todo Can we determine the host OS? On X11 a resize() is sufficient! - eventObservers.front()->initialize(m_CurrentWidth, m_CurrentHeight, 0, true); + eventObservers.front()->initialize(m_CurrentWidth, m_CurrentHeight, getDisplayScalingFactor(), 0, true); } void WindowManager::setScreensaverMode(const bool enabled) { m_ScreensaverMode = enabled; } + +float WindowManager::getDisplayScalingFactor() { + // DPI at which the reference layout was built + const float defaultDPI = DESIGN_DPI; + + float vDPI; + float hDPI; + float dDPI; + + int displayIndex = SDL_GetWindowDisplayIndex(m_Window); + if(displayIndex < 0 || SDL_GetDisplayDPI(displayIndex, &dDPI, &hDPI, &vDPI) != 0) + { + // Failed to get DPI, so return no scaling + cerr << "Could not determine display DPI: " << SDL_GetError() << endl; + return 1.0; + } + + // cout << "Display DPI (v/h/d): " << vDPI <<" / " << hDPI << " / " << dDPI << endl; + + // finally, return scaling factor; + return hDPI / defaultDPI; +} diff --git a/src/framework/WindowManager.h b/src/framework/WindowManager.h index d598daf..70b8814 100644 --- a/src/framework/WindowManager.h +++ b/src/framework/WindowManager.h @@ -222,6 +222,9 @@ private: */ static Uint32 timerCallbackBOINCUpdateEvent(Uint32 interval, void *param); + /// Returns the HDPI scaling factor for the current window + float getDisplayScalingFactor(); + /// Local BOINC adapter instance to read project preferences BOINCClientAdapter *m_BoincAdapter; diff --git a/src/starsphere/Starsphere.cpp b/src/starsphere/Starsphere.cpp index a7ecf9a..79c00ea 100644 --- a/src/starsphere/Starsphere.cpp +++ b/src/starsphere/Starsphere.cpp @@ -588,7 +588,7 @@ void Starsphere::resize(const int width, const int height) aspect = (float)width / (float)height; // adjust HUD config - m_YStartPosTop = height - 25; + m_YStartPosTop = height - 65; // make sure the search marker is updated (conditional rendering!) m_RefreshSearchMarker = true; @@ -604,8 +604,10 @@ void Starsphere::resize(const int width, const int height) /** * What to do when graphics are "initialized". */ -void Starsphere::initialize(const int width, const int height, const Resource *font, const bool recycle) +void Starsphere::initialize(const int width, const int height, const float scale, const Resource *font, const bool recycle) { + AbstractGraphicsEngine::initialize(width, height, scale, font, recycle); + // check whether we initialize the first time or have to recycle (required for windoze) if(!recycle) { @@ -616,8 +618,8 @@ void Starsphere::initialize(const int width, const int height, const Resource *f m_BoincAdapter.initialize(); // inital HUD offset setup - m_XStartPosLeft = 5; - m_YOffsetLarge = 18; + m_XStartPosLeft = 20 * m_Scale; + m_YOffsetLarge = 35 * m_Scale; setFeature(STARS, true); setFeature(CONSTELLATIONS, true); @@ -652,7 +654,7 @@ void Starsphere::initialize(const int width, const int height, const Resource *f m_FontHeader = new OGLFT::TranslucentTexture( &m_FontResource->data()->at(0), m_FontResource->data()->size(), - 13, 78 ); + 20, uint(DESIGN_DPI) ); if ( m_FontHeader == 0 || !m_FontHeader->isValid() ) { cerr << "Could not construct header font face from in memory resource!" << endl; @@ -665,7 +667,7 @@ void Starsphere::initialize(const int width, const int height, const Resource *f m_FontText = new OGLFT::TranslucentTexture( &m_FontResource->data()->at(0), m_FontResource->data()->size(), - 11, 72 ); + 16, uint(DESIGN_DPI) ); if ( m_FontText == 0 || !m_FontText->isValid() ) { cerr << "Could not construct text font face from in memory resource!" << endl; diff --git a/src/starsphere/Starsphere.h b/src/starsphere/Starsphere.h index 7e73625..ba8a2da 100644 --- a/src/starsphere/Starsphere.h +++ b/src/starsphere/Starsphere.h @@ -96,10 +96,11 @@ public: * * \param width The current width of the display surface * \param height The current height of the display surface + * \param scale The scaling factor on HDPI displays * \param font A pointer to a Resource object containing TTF font faces for text rendering * \param recycle This flag indicates whether we initialize (FALSE) or reinitialize (TRUE) the context */ - virtual void initialize(const int width, const int height, const Resource *font, const bool recycle = false); + virtual void initialize(const int width, const int height, const float scale, const Resource *font, const bool recycle = false); /** * \brief This method is called when the windowing system encounters a window resize event diff --git a/src/starsphere/StarsphereRadio.cpp b/src/starsphere/StarsphereRadio.cpp index 6afb58b..17e265f 100644 --- a/src/starsphere/StarsphereRadio.cpp +++ b/src/starsphere/StarsphereRadio.cpp @@ -34,9 +34,9 @@ StarsphereRadio::~StarsphereRadio() { } -void StarsphereRadio::initialize(const int width, const int height, const Resource *font, const bool recycle) +void StarsphereRadio::initialize(const int width, const int height, const float scale, const Resource *font, const bool recycle) { - Starsphere::initialize(width, height, font, recycle); + Starsphere::initialize(width, height, scale, font, recycle); // store quality setting m_QualitySetting = m_BoincAdapter.graphicsQualitySetting(); @@ -45,10 +45,10 @@ void StarsphereRadio::initialize(const int width, const int height, const Resour if(!recycle) { // adjust HUD config - m_YOffsetMedium = 15.0; - m_XStartPosRightWidthOffset = 125.0; + m_YOffsetMedium = 34.0 * m_Scale; + m_XStartPosRightWidthOffset = 325.0 * m_Scale; m_XStartPosRight = width - m_XStartPosRightWidthOffset; - m_YStartPosBottom = 100.0; + m_YStartPosBottom = 225.0 * m_Scale; m_Y1StartPosBottom = m_YStartPosBottom - m_YOffsetMedium; m_Y2StartPosBottom = m_Y1StartPosBottom - m_YOffsetMedium; m_Y3StartPosBottom = m_Y2StartPosBottom - m_YOffsetMedium; @@ -57,17 +57,17 @@ void StarsphereRadio::initialize(const int width, const int height, const Resour m_Y6StartPosBottom = m_Y5StartPosBottom - m_YOffsetMedium; // adjust Power Spectrum config - m_PowerSpectrumWidth = 200.0; - m_PowerSpectrumHeight = 50.0; - m_PowerSpectrumOriginWidthOffset = 210.0; - m_PowerSpectrumOriginHeightOffset = 60.0; + m_PowerSpectrumWidth = 410.0 * m_Scale; + m_PowerSpectrumHeight = 80.0 * m_Scale; + m_PowerSpectrumOriginWidthOffset = 430.0 * m_Scale; + m_PowerSpectrumOriginHeightOffset = 95.0 * m_Scale; m_PowerSpectrumXPos = width - m_PowerSpectrumOriginWidthOffset; m_PowerSpectrumYPos = height - m_PowerSpectrumOriginHeightOffset; - m_PowerSpectrumAxesWidth = 2.0; - m_PowerSpectrumBinWidth = 3.0; - m_PowerSpectrumBinDistance = 2.0; - m_PowerSpectrumLabelXOffset = (m_PowerSpectrumWidth - 150.0) / 2; - m_PowerSpectrumLabelYOffset = 15.0; + m_PowerSpectrumAxesWidth = 2.0 * m_Scale; + m_PowerSpectrumBinWidth = 6.2 * m_Scale; + m_PowerSpectrumBinDistance = 4.0 * m_Scale; + m_PowerSpectrumLabelXOffset = (m_PowerSpectrumWidth - 290.0 * m_Scale) / 2; + m_PowerSpectrumLabelYOffset = 30.0 * m_Scale; m_PowerSpectrumLabelXPos = m_PowerSpectrumXPos + m_PowerSpectrumLabelXOffset; m_PowerSpectrumLabelYPos = m_PowerSpectrumYPos - m_PowerSpectrumLabelYOffset; } @@ -76,7 +76,7 @@ void StarsphereRadio::initialize(const int width, const int height, const Resour m_FontLogo1 = new OGLFT::TranslucentTexture( &m_FontResource->data()->at(0), m_FontResource->data()->size(), - 26, 78 ); + 36, uint(DESIGN_DPI) ); if ( m_FontLogo1 == 0 || !m_FontLogo1->isValid() ) { cerr << "Could not construct logo1 font face from in memory resource!" << endl; @@ -89,7 +89,7 @@ void StarsphereRadio::initialize(const int width, const int height, const Resour m_FontLogo2 = new OGLFT::TranslucentTexture( &m_FontResource->data()->at(0), m_FontResource->data()->size(), - 12, 72 ); + 15.5, uint(DESIGN_DPI) ); if ( m_FontLogo2 == 0 || !m_FontLogo2->isValid() ) { cerr << "Could not construct logo2 font face from in memory resource!" << endl; @@ -227,7 +227,7 @@ void StarsphereRadio::renderSearchInformation() m_FontText->draw(m_XStartPosRight, m_Y6StartPosBottom, m_WUTemplateOrbitalPhase.c_str()); // power spectrum label - m_FontText->draw(m_PowerSpectrumLabelXPos, m_PowerSpectrumLabelYPos, "Radio Signal Power Spectrum"); + m_FontLogo2->draw(m_PowerSpectrumLabelXPos, m_PowerSpectrumLabelYPos, "Radio Power Spectrum"); // disable opt-in quality feature for power spectrum if(m_QualitySetting == BOINCClientAdapter::HighGraphicsQualitySetting) { @@ -288,7 +288,7 @@ void StarsphereRadio::generatePowerSpectrumBins(const int originX, const int ori { GLfloat offsetX = (GLfloat)originX; GLfloat offsetY = (GLfloat)originY; - GLfloat axesXOffset = m_PowerSpectrumAxesWidth + 2; + GLfloat axesXOffset = m_PowerSpectrumBinWidth + m_PowerSpectrumBinDistance / 2.0; GLfloat axesYOffset = m_PowerSpectrumAxesWidth / 2.0 + 1; GLfloat binXOffset = m_PowerSpectrumBinWidth + m_PowerSpectrumBinDistance; diff --git a/src/starsphere/StarsphereRadio.h b/src/starsphere/StarsphereRadio.h index 7a8b5d3..b41397d 100644 --- a/src/starsphere/StarsphereRadio.h +++ b/src/starsphere/StarsphereRadio.h @@ -71,10 +71,11 @@ public: * * \param width The current width of the display surface * \param height The current height of the display surface + * \param scale The scaling factor on HDPI displays * \param font A pointer to a Resource object containing TTF font faces for text rendering * \param recycle This flag indicates whether we initialize (FALSE) or reinitialize (TRUE) the context */ - virtual void initialize(const int width, const int height, const Resource *font, const bool recycle = false); + virtual void initialize(const int width, const int height, const float scale, const Resource *font, const bool recycle = false); /** * \brief This method is called when the windowing system encounters a window resize event diff --git a/src/starsphere/StarsphereS5R3.cpp b/src/starsphere/StarsphereS5R3.cpp index e93e332..cbee93a 100644 --- a/src/starsphere/StarsphereS5R3.cpp +++ b/src/starsphere/StarsphereS5R3.cpp @@ -33,29 +33,32 @@ StarsphereS5R3::~StarsphereS5R3() { } -void StarsphereS5R3::initialize(const int width, const int height, const Resource *font, const bool recycle) +void StarsphereS5R3::initialize(const int width, const int height, const float scale, const Resource *font, const bool recycle) { - Starsphere::initialize(width, height, font, recycle); + Starsphere::initialize(width, height, scale, font, recycle); // check whether we initialize the first time or have to recycle (required for windoze) if(!recycle) { // adjust HUD config - m_YOffsetMedium = 15; - m_XStartPosRight = width - 125; - m_XStartPosClock = width - 98; - m_YStartPosBottom = 70; + m_YOffsetMedium = 34.0 * m_Scale; + m_XStartPosRightWidthOffset = 325 * m_Scale; + m_XStartPosRight = width - m_XStartPosRightWidthOffset; + m_XStartPosClockWidthOffset = 270 * m_Scale; + m_XStartPosClock = width - m_XStartPosClockWidthOffset; + m_YStartPosBottom = 160 * m_Scale; m_Y1StartPosBottom = m_YStartPosBottom - m_YOffsetMedium; m_Y2StartPosBottom = m_Y1StartPosBottom - m_YOffsetMedium; m_Y3StartPosBottom = m_Y2StartPosBottom - m_YOffsetMedium; m_Y4StartPosBottom = m_Y3StartPosBottom - m_YOffsetMedium; + m_Logo2XOffset = 60; } // create large font instances using font resource (base address + size) m_FontLogo1 = new OGLFT::TranslucentTexture( &m_FontResource->data()->at(0), m_FontResource->data()->size(), - 24, 72 ); + 36, uint(DESIGN_DPI) ); if ( m_FontLogo1 == 0 || !m_FontLogo1->isValid() ) { cerr << "Could not construct logo1 font face from in memory resource!" << endl; @@ -68,7 +71,7 @@ void StarsphereS5R3::initialize(const int width, const int height, const Resourc m_FontLogo2 = new OGLFT::TranslucentTexture( &m_FontResource->data()->at(0), m_FontResource->data()->size(), - 13, 78 ); + 16, uint(DESIGN_DPI) ); if ( m_FontLogo2 == 0 || !m_FontLogo2->isValid() ) { cerr << "Could not construct logo2 font face from in memory resource!" << endl; @@ -86,8 +89,8 @@ void StarsphereS5R3::resize(const int width, const int height) Starsphere::resize(width, height); // adjust HUD config - m_XStartPosRight = width - 125; - m_XStartPosClock = width - 98; + m_XStartPosRight = width - m_XStartPosRightWidthOffset; + m_XStartPosClock = width - m_XStartPosClockWidthOffset; } void StarsphereS5R3::refreshBOINCInformation() @@ -179,5 +182,5 @@ void StarsphereS5R3::generateObservatories(float dimFactor) void StarsphereS5R3::renderLogo() { m_FontLogo1->draw(m_XStartPosLeft, m_YStartPosTop, "Einstein@Home"); - m_FontLogo2->draw(m_XStartPosLeft, m_YStartPosTop - m_YOffsetLarge, "World Year of Physics 2005"); + m_FontLogo2->draw(m_XStartPosLeft + m_Logo2XOffset, m_YStartPosTop - m_YOffsetLarge, "World Year of Physics 2005"); } diff --git a/src/starsphere/StarsphereS5R3.h b/src/starsphere/StarsphereS5R3.h index 915dba5..7e59e2e 100644 --- a/src/starsphere/StarsphereS5R3.h +++ b/src/starsphere/StarsphereS5R3.h @@ -64,10 +64,11 @@ public: * * \param width The current width of the display surface * \param height The current height of the display surface + * \param scale The scaling factor on HDPI displays * \param font A pointer to a Resource object containing TTF font faces for text rendering * \param recycle This flag indicates whether we initialize (FALSE) or reinitialize (TRUE) the context */ - virtual void initialize(const int width, const int height, const Resource *font, const bool recycle = false); + virtual void initialize(const int width, const int height, const float scale, const Resource *font, const bool recycle = false); /** * \brief This method is called when the windowing system encounters a window resize event @@ -139,9 +140,15 @@ private: /// HUD configuration setting (line offset for medium sized font) GLfloat m_YOffsetMedium; + /// HUD configuration setting (horizontal offset of the right part) + GLfloat m_XStartPosRightWidthOffset; + /// HUD configuration setting (horizontal start position for the right part) GLfloat m_XStartPosRight; + /// HUD configuration setting (horizontal offset of the clock display) + GLfloat m_XStartPosClockWidthOffset; + /// HUD configuration setting (horizontal start position for the clock display) GLfloat m_XStartPosClock; @@ -159,6 +166,9 @@ private: /// HUD configuration setting (vertical start postion for the bottom part, line 4) GLfloat m_Y4StartPosBottom; + + /// HUD configuration setting (horizontal offset of logo, line 2) + GLfloat m_Logo2XOffset; }; /** diff --git a/src/starsphere/main.cpp b/src/starsphere/main.cpp index df55fce..25441b8 100644 --- a/src/starsphere/main.cpp +++ b/src/starsphere/main.cpp @@ -123,7 +123,7 @@ int main(int argc, char **argv) window.registerEventObserver(graphics); // pepare rendering - graphics->initialize(window.windowWidth(), window.windowHeight(), fontResource); + graphics->initialize(window.windowWidth(), window.windowHeight(), 1.0, fontResource); graphics->refreshBOINCInformation(); // check optional command line parameters -- GitLab