Mana
Loading...
Searching...
No Matches
truetypefont.cpp
Go to the documentation of this file.
1/*
2 * The Mana Client
3 * Copyright (C) 2004-2009 The Mana World Development Team
4 * Copyright (C) 2009-2012 The Mana Developers
5 * Copyright (C) 2009 Aethyra Development Team
6 *
7 * This file is part of The Mana Client.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include "gui/truetypefont.h"
24
25#include "graphics.h"
26
27#include "resources/image.h"
28
29#include <guichan/color.hpp>
30#include <guichan/exception.hpp>
31
32#include <cmath>
33#include <memory>
34
35const unsigned int CACHE_SIZE = 256;
36
37static const char *getSafeUtf8String(const std::string &text)
38{
39 static int UTF8_MAX_SIZE = 10;
40
41 static char buf[4096];
42 const int len = std::min(text.size(), sizeof(buf) - UTF8_MAX_SIZE);
43 memcpy(buf, text.c_str(), len);
44 memset(buf + len, 0, UTF8_MAX_SIZE);
45 return buf;
46}
47
48
50{
51public:
52 TextChunk(const std::string &text)
53 : text(text)
54 {}
55
57 int x, int y,
58 TTF_Font *font,
59 std::unique_ptr<Image> &img,
60 float scale);
61
62 const std::string text;
63 std::unique_ptr<Image> regular;
64 std::unique_ptr<Image> outlined;
65};
66
68 int x, int y,
69 TTF_Font *font,
70 std::unique_ptr<Image> &img,
71 float scale)
72{
73 if (!img)
74 {
75 // Always render in white, we'll use color modulation when rendering
76 constexpr SDL_Color white = { 255, 255, 255, 255 };
77 SDL_Surface *surface = TTF_RenderUTF8_Blended(font,
78 getSafeUtf8String(text),
79 white);
80
81 if (surface)
82 {
83 img.reset(Image::load(surface));
84 SDL_FreeSurface(surface);
85 }
86 }
87
88 if (img)
89 {
90 graphics->drawRescaledImageF(img.get(), 0, 0, x, y,
91 img->getWidth(),
92 img->getHeight(),
93 img->getWidth() / scale,
94 img->getHeight() / scale, true);
95
96 }
97}
98
99
100std::list<TrueTypeFont*> TrueTypeFont::mFonts;
101float TrueTypeFont::mScale = 1.0f;
102
103TrueTypeFont::TrueTypeFont(const std::string &filename, int size, int style)
104 : mFilename(filename)
105 , mPointSize(size)
106 , mStyle(style)
107{
108 if (TTF_Init() == -1)
109 {
110 throw GCN_EXCEPTION("Unable to initialize SDL_ttf: " +
111 std::string(TTF_GetError()));
112 }
113
114 mFont = TTF_OpenFont(filename.c_str(), size * mScale);
115 mFontOutline = TTF_OpenFont(filename.c_str(), size * mScale);
116
117 if (!mFont || !mFontOutline)
118 {
119 throw GCN_EXCEPTION("SDLTrueTypeFont::SDLTrueTypeFont: " +
120 std::string(TTF_GetError()));
121 }
122
123 TTF_SetFontStyle(mFont, style);
124 TTF_SetFontStyle(mFontOutline, style);
125
126 TTF_SetFontOutline(mFontOutline, static_cast<int>(mScale));
127
128 mFonts.push_back(this);
129}
130
132{
133 mFonts.remove(this);
134
135 if (mFont)
136 TTF_CloseFont(mFont);
137
138 if (mFontOutline)
139 TTF_CloseFont(mFontOutline);
140
141 TTF_Quit();
142}
143
145 const std::string &text,
146 int x, int y)
147{
148 if (text.empty())
149 return;
150
151 auto *g = static_cast<Graphics *>(graphics);
152 TextChunk &chunk = getChunk(text);
153
154 chunk.render(g, x, y, mFont, chunk.regular, mScale);
155}
156
158 const std::string &text,
159 int x, int y,
160 const std::optional<gcn::Color> &outlineColor,
161 const std::optional<gcn::Color> &shadowColor)
162{
163 if (text.empty())
164 return;
165
166 auto *g = static_cast<Graphics *>(graphics);
167 auto color = graphics->getColor();
168 TextChunk &chunk = getChunk(text);
169
170 if (shadowColor)
171 {
172 g->setColor(*shadowColor);
173 if (outlineColor)
174 chunk.render(g, x, y, mFontOutline, chunk.outlined, mScale);
175 else
176 chunk.render(g, x + 1, y + 1, mFont, chunk.regular, mScale);
177 }
178
179 if (outlineColor)
180 {
181 g->setColor(*outlineColor);
182 chunk.render(g, x - 1, y - 1, mFontOutline, chunk.outlined, mScale);
183 }
184
185 g->setColor(color);
186 chunk.render(g, x, y, mFont, chunk.regular, mScale);
187}
188
190{
191 if (mScale == scale)
192 return;
193
194 mScale = scale;
195
196 for (auto font : mFonts)
197 {
198#if SDL_TTF_VERSION_ATLEAST(2, 0, 18)
199 TTF_SetFontSize(font->mFont, font->mPointSize * mScale);
200 TTF_SetFontSize(font->mFontOutline, font->mPointSize * mScale);
201 TTF_SetFontOutline(font->mFontOutline, mScale);
202#else
203 TTF_CloseFont(font->mFont);
204 TTF_CloseFont(font->mFontOutline);
205 font->mFont = TTF_OpenFont(font->mFilename.c_str(), font->mPointSize * mScale);
206 font->mFontOutline = TTF_OpenFont(font->mFilename.c_str(), font->mPointSize * mScale);
207 TTF_SetFontStyle(font->mFont, font->mStyle);
208 TTF_SetFontStyle(font->mFontOutline, font->mStyle);
209 TTF_SetFontOutline(font->mFontOutline, mScale);
210#endif
211
212 font->mCache.clear();
213 }
214}
215
216int TrueTypeFont::getWidth(const std::string &text) const
217{
218 TextChunk &chunk = getChunk(text);
219 if (auto img = chunk.regular.get())
220 return std::ceil(img->getWidth() / mScale);
221
222 // If the image wasn't created yet, just calculate the width of the text
223 int w, h;
224 TTF_SizeUTF8(mFont, getSafeUtf8String(text), &w, &h);
225 return std::ceil(w / mScale);
226}
227
229{
230 return std::ceil(TTF_FontHeight(mFont) / mScale);
231}
232
234{
235 return std::ceil(TTF_FontLineSkip(mFont) / mScale);
236}
237
238TextChunk &TrueTypeFont::getChunk(const std::string &text) const
239{
240 for (auto i = mCache.begin(); i != mCache.end(); i++)
241 {
242 if (i->text == text)
243 {
244 // Raise priority: move it to front
245 mCache.splice(mCache.begin(), mCache, i);
246 return *i;
247 }
248 }
249
250 if (mCache.size() >= CACHE_SIZE)
251 mCache.pop_back();
252
253 return mCache.emplace_front(text);
254}
A central point of control for graphics.
Definition graphics.h:78
const gcn::Color & getColor() const final
Definition graphics.h:260
virtual bool drawRescaledImageF(const Image *image, int srcX, int srcY, float dstX, float dstY, int width, int height, float desiredWidth, float desiredHeight, bool useColor=false)
Draws a rescaled version of the image.
Definition graphics.cpp:60
static Resource * load(SDL_RWops *rw)
Loads an image from an SDL_RWops structure.
Definition image.cpp:98
std::unique_ptr< Image > regular
TextChunk(const std::string &text)
std::unique_ptr< Image > outlined
const std::string text
void render(Graphics *graphics, int x, int y, TTF_Font *font, std::unique_ptr< Image > &img, float scale)
~TrueTypeFont() override
int getWidth(const std::string &text) const override
static std::list< TrueTypeFont * > mFonts
TTF_Font * mFont
static void updateFontScale(float scale)
TextChunk & getChunk(const std::string &text) const
TTF_Font * mFontOutline
int getLineHeight() const
Returns the height of a line of text.
static float mScale
const std::string & filename() const
int style() const
TrueTypeFont(const std::string &filename, int size, int style=0)
Constructor.
std::list< TextChunk > mCache
int getHeight() const override
void drawString(gcn::Graphics *graphics, const std::string &text, int x, int y) override
Graphics * graphics
Definition client.cpp:104
const unsigned int CACHE_SIZE