diff options
author | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2024-03-25 08:29:53 +0100 |
---|---|---|
committer | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2024-03-26 07:30:39 +0000 |
commit | da7a32c6ea92242c99412c2702ad59df36007de4 (patch) | |
tree | 79bea6d27c808d4fe5ac63941f8cbb52afb34552 | |
parent | 4091bd9568e5aff4a1f24416d26da567a2c076ad (diff) | |
download | mana-da7a32c6ea92242c99412c2702ad59df36007de4.tar.gz mana-da7a32c6ea92242c99412c2702ad59df36007de4.tar.bz2 mana-da7a32c6ea92242c99412c2702ad59df36007de4.tar.xz mana-da7a32c6ea92242c99412c2702ad59df36007de4.zip |
Added support for HiDPI fonts
* TrueTypeFont class now takes into account the graphics scale, in order
to render an appropriate higher-resolution texture.
* Removed TrueTypeFont::fontCounter, since TTF_Init/TTF_Quit already
keep a counter.
* Avoid copying the rendered string needlessly, when it already exists
in the cache. Avoid another copy, when inserting a new chunk into the
cache.
-rw-r--r-- | src/client.cpp | 5 | ||||
-rw-r--r-- | src/graphics.h | 6 | ||||
-rw-r--r-- | src/gui/gui.cpp | 10 | ||||
-rw-r--r-- | src/gui/gui.h | 4 | ||||
-rw-r--r-- | src/gui/truetypefont.cpp | 154 | ||||
-rw-r--r-- | src/gui/truetypefont.h | 8 | ||||
-rw-r--r-- | src/openglgraphics.cpp | 11 | ||||
-rw-r--r-- | src/openglgraphics.h | 2 | ||||
-rw-r--r-- | src/sdlgraphics.cpp | 1 |
9 files changed, 120 insertions, 81 deletions
diff --git a/src/client.cpp b/src/client.cpp index 7d887436..8e144e8e 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1339,12 +1339,9 @@ void Client::checkGraphicsSize() const int width = graphics->getWidth(); const int height = graphics->getHeight(); - const auto guiTop = gui->getTop(); - if (guiTop->getWidth() == width && guiTop->getHeight() == height) + if (!gui->videoResized(width, height)) return; - gui->videoResized(width, height); - if (mDesktop) mDesktop->setSize(width, height); diff --git a/src/graphics.h b/src/graphics.h index 79513e2c..55f67568 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -203,6 +203,11 @@ class Graphics : public gcn::Graphics int getHeight() const { return mHeight; } /** + * Returns the graphics scale. + */ + float getScale() const { return mScale; } + + /** * Converts a window coordinate to a logical coordinate. Used for * converting mouse coordinates. */ @@ -237,6 +242,7 @@ class Graphics : public gcn::Graphics protected: int mWidth = 0; int mHeight = 0; + float mScale = 1.0f; gcn::Color mColor; }; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 68f43cc3..ae74cab2 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -106,6 +106,9 @@ Gui::Gui(Graphics *graphics) std::string fontFile = branding.getValue("font", "fonts/dejavusans.ttf"); std::string path = resman->getPath(fontFile); + // Initialize the font scale before creating the fonts + TrueTypeFont::updateFontScale(graphics->getScale()); + try { mGuiFont = new TrueTypeFont(path, fontSize); @@ -222,17 +225,20 @@ void Gui::draw() mGraphics->_endDraw(); } -void Gui::videoResized(int width, int height) +bool Gui::videoResized(int width, int height) { + TrueTypeFont::updateFontScale(static_cast<Graphics*>(mGraphics)->getScale()); + auto *top = static_cast<WindowContainer*>(getTop()); int oldWidth = top->getWidth(); int oldHeight = top->getHeight(); if (oldWidth == width && oldHeight == height) - return; + return false; top->setSize(width, height); top->adjustAfterResize(oldWidth, oldHeight); + return true; } void Gui::setUseCustomCursor(bool customCursor) diff --git a/src/gui/gui.h b/src/gui/gui.h index b731514f..29dcdef2 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -86,8 +86,10 @@ class Gui : public gcn::Gui /** * Called when the application window has been resized. + * + * Returns whether the top widget changed size. */ - void videoResized(int width, int height); + bool videoResized(int width, int height); gcn::FocusHandler *getFocusHandler() const { return mFocusHandler; } diff --git a/src/gui/truetypefont.cpp b/src/gui/truetypefont.cpp index adb49780..30037f84 100644 --- a/src/gui/truetypefont.cpp +++ b/src/gui/truetypefont.cpp @@ -29,6 +29,9 @@ #include <guichan/color.hpp> #include <guichan/exception.hpp> +#include <cmath> +#include <memory> + const unsigned int CACHE_SIZE = 256; static const char *getSafeUtf8String(const std::string &text) @@ -42,64 +45,55 @@ static const char *getSafeUtf8String(const std::string &text) return buf; } -class TextChunk +bool operator==(SDL_Color lhs, SDL_Color rhs) { - public: - TextChunk(const std::string &text, const gcn::Color &color) : - text(text), color(color) - { - } - - ~TextChunk() - { - delete img; - } - - bool operator==(const TextChunk &chunk) const - { - return (chunk.text == text && chunk.color == color); - } + return (lhs.r == rhs.r && + lhs.g == rhs.g && + lhs.b == rhs.b && + lhs.a == rhs.a); +} - void generate(TTF_Font *font) - { - SDL_Color sdlCol; - sdlCol.r = color.r; - sdlCol.g = color.g; - sdlCol.b = color.b; - sdlCol.a = color.a; +class TextChunk +{ +public: + TextChunk(const std::string &text, SDL_Color color) + : text(text) + , color(color) + {} - const char *str = getSafeUtf8String(text); - SDL_Surface *surface = TTF_RenderUTF8_Blended( - font, str, sdlCol); + void generate(TTF_Font *font) + { + SDL_Surface *surface = TTF_RenderUTF8_Blended(font, + getSafeUtf8String(text), + color); - if (!surface) - { - img = nullptr; - return; - } + if (!surface) + return; - img = Image::load(surface); + img.reset(Image::load(surface)); - SDL_FreeSurface(surface); - } + SDL_FreeSurface(surface); + } - Image *img = nullptr; - std::string text; - gcn::Color color; + std::unique_ptr<Image> img; + const std::string text; + const SDL_Color color; }; -static int fontCounter; +std::list<TrueTypeFont*> TrueTypeFont::mFonts; +float TrueTypeFont::mScale = 1.0f; TrueTypeFont::TrueTypeFont(const std::string &filename, int size, int style) + : mFilename(filename) + , mPointSize(size) { - if (fontCounter == 0 && TTF_Init() == -1) + if (TTF_Init() == -1) { throw GCN_EXCEPTION("Unable to initialize SDL_ttf: " + std::string(TTF_GetError())); } - ++fontCounter; - mFont = TTF_OpenFont(filename.c_str(), size); + mFont = TTF_OpenFont(filename.c_str(), size * mScale); if (!mFont) { @@ -108,15 +102,18 @@ TrueTypeFont::TrueTypeFont(const std::string &filename, int size, int style) } TTF_SetFontStyle(mFont, style); + + mFonts.push_back(this); } TrueTypeFont::~TrueTypeFont() { - TTF_CloseFont(mFont); - --fontCounter; + mFonts.remove(this); + + if (mFont) + TTF_CloseFont(mFont); - if (fontCounter == 0) - TTF_Quit(); + TTF_Quit(); } void TrueTypeFont::drawString(gcn::Graphics *graphics, @@ -126,26 +123,25 @@ void TrueTypeFont::drawString(gcn::Graphics *graphics, if (text.empty()) return; - auto *g = dynamic_cast<Graphics *>(graphics); + auto *g = static_cast<Graphics *>(graphics); + const gcn::Color col = g->getColor(); - if (!g) - throw "Not a valid graphics object!"; - - gcn::Color col = g->getColor(); - const float alpha = col.a / 255.0f; - - /* The alpha value is ignored at string generation so avoid caching the + /* The alpha value is ignored at image generation to avoid caching the * same text with different alpha values. */ - col.a = 255; - - TextChunk chunk(text, col); + const SDL_Color color = { + static_cast<Uint8>(col.r), + static_cast<Uint8>(col.g), + static_cast<Uint8>(col.b), + 255 + }; bool found = false; for (auto i = mCache.begin(); i != mCache.end(); ++i) { - if (chunk == (*i)) + auto &chunk = *i; + if (chunk.text == text && chunk.color == color) { // Raise priority: move it to front mCache.splice(mCache.begin(), mCache, i); @@ -154,19 +150,42 @@ void TrueTypeFont::drawString(gcn::Graphics *graphics, } } - // Surface not found if (!found) { if (mCache.size() >= CACHE_SIZE) mCache.pop_back(); - mCache.push_front(chunk); + mCache.emplace_front(text, color); mCache.front().generate(mFont); } - if (mCache.front().img) + if (auto img = mCache.front().img.get()) + { + img->setAlpha(col.a / 255.0f); + g->drawRescaledImageF(img, 0, 0, x, y, + img->getWidth(), + img->getHeight(), + img->getWidth() / mScale, + img->getHeight() / mScale); + } +} + +void TrueTypeFont::updateFontScale(float scale) +{ + if (mScale == scale) + return; + + mScale = scale; + + for (auto font : mFonts) { - mCache.front().img->setAlpha(alpha); - g->drawImage(mCache.front().img, x, y); +#if SDL_TTF_VERSION_ATLEAST(2, 0, 18) + TTF_SetFontSize(font->mFont, font->mPointSize * mScale); +#else + TTF_CloseFont(font->mFont); + font->mFont = TTF_OpenFont(font->mFilename.c_str(), font->mPointSize * mScale); +#endif + + font->mCache.clear(); } } @@ -180,23 +199,22 @@ int TrueTypeFont::getWidth(const std::string &text) const // Assumption is that TTF::draw will be called next mCache.splice(mCache.begin(), mCache, i); if (i->img) - return i->img->getWidth(); + return std::ceil(i->img->getWidth() / mScale); return 0; } } int w, h; - const char *str = getSafeUtf8String(text); - TTF_SizeUTF8(mFont, str, &w, &h); - return w; + TTF_SizeUTF8(mFont, getSafeUtf8String(text), &w, &h); + return std::ceil(w / mScale); } int TrueTypeFont::getHeight() const { - return TTF_FontHeight(mFont); + return std::ceil(TTF_FontHeight(mFont) / mScale); } int TrueTypeFont::getLineHeight() const { - return TTF_FontLineSkip(mFont); + return std::ceil(TTF_FontLineSkip(mFont) / mScale); } diff --git a/src/gui/truetypefont.h b/src/gui/truetypefont.h index d42400d8..b3ebcc73 100644 --- a/src/gui/truetypefont.h +++ b/src/gui/truetypefont.h @@ -72,11 +72,19 @@ class TrueTypeFont : public gcn::Font const std::string &text, int x, int y) override; + static void updateFontScale(float scale); + private: + const std::string mFilename; TTF_Font *mFont; + const int mPointSize; + // Word surfaces cache mutable std::list<TextChunk> mCache; + + static std::list<TrueTypeFont*> mFonts; + static float mScale; }; #endif diff --git a/src/openglgraphics.cpp b/src/openglgraphics.cpp index 9e77e5f7..56c16586 100644 --- a/src/openglgraphics.cpp +++ b/src/openglgraphics.cpp @@ -131,7 +131,7 @@ void OpenGLGraphics::setReduceInputLag(bool reduceInputLag) void OpenGLGraphics::updateSize(int windowWidth, int windowHeight, float scale) { - mScale = scale; + mUserScale = scale; int drawableWidth; int drawableHeight; @@ -142,11 +142,12 @@ void OpenGLGraphics::updateSize(int windowWidth, int windowHeight, float scale) float displayScaleX = windowWidth > 0 ? static_cast<float>(drawableWidth) / windowWidth : 1.0f; float displayScaleY = windowHeight > 0 ? static_cast<float>(drawableHeight) / windowHeight : 1.0f; - mScaleX = mScale * displayScaleX; - mScaleY = mScale * displayScaleY; + mScaleX = mUserScale * displayScaleX; + mScaleY = mUserScale * displayScaleY; mWidth = std::ceil(drawableWidth / mScaleX); mHeight = std::ceil(drawableHeight / mScaleY); + mScale = mScaleX; glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -557,8 +558,8 @@ void OpenGLGraphics::updateScreen() void OpenGLGraphics::windowToLogical(int windowX, int windowY, float &logicalX, float &logicalY) const { - logicalX = windowX / mScale; - logicalY = windowY / mScale; + logicalX = windowX / mUserScale; + logicalY = windowY / mUserScale; } SDL_Surface *OpenGLGraphics::getScreenshot() diff --git a/src/openglgraphics.h b/src/openglgraphics.h index dbeab80a..654a7194 100644 --- a/src/openglgraphics.h +++ b/src/openglgraphics.h @@ -126,7 +126,7 @@ class OpenGLGraphics final : public Graphics GLfloat *mFloatTexArray; GLint *mIntTexArray; GLint *mIntVertArray; - float mScale = 1.0f; + float mUserScale = 1.0f; float mScaleX = 1.0f; float mScaleY = 1.0f; bool mAlpha = false; diff --git a/src/sdlgraphics.cpp b/src/sdlgraphics.cpp index dc56496e..a2fc2268 100644 --- a/src/sdlgraphics.cpp +++ b/src/sdlgraphics.cpp @@ -101,6 +101,7 @@ void SDLGraphics::updateSize(int windowWidth, int windowHeight, float scale) mWidth = std::ceil(mWidth / scaleX); mHeight = std::ceil(mHeight / scaleY); + mScale = scaleX; SDL_RenderSetScale(mRenderer, scaleX, scaleY); } |