summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <bjorn@lindeijer.nl>2024-03-25 08:29:53 +0100
committerThorbjørn Lindeijer <bjorn@lindeijer.nl>2024-03-26 07:30:39 +0000
commitda7a32c6ea92242c99412c2702ad59df36007de4 (patch)
tree79bea6d27c808d4fe5ac63941f8cbb52afb34552
parent4091bd9568e5aff4a1f24416d26da567a2c076ad (diff)
downloadmana-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.cpp5
-rw-r--r--src/graphics.h6
-rw-r--r--src/gui/gui.cpp10
-rw-r--r--src/gui/gui.h4
-rw-r--r--src/gui/truetypefont.cpp154
-rw-r--r--src/gui/truetypefont.h8
-rw-r--r--src/openglgraphics.cpp11
-rw-r--r--src/openglgraphics.h2
-rw-r--r--src/sdlgraphics.cpp1
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);
}