1 /*
2 * Copyright (C) 2006-2019 Christopho, Solarus - http://www.solarus-games.org
3 *
4 * Solarus is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Solarus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include "solarus/core/CurrentQuest.h"
18 #include "solarus/core/Debug.h"
19 #include "solarus/core/FontResource.h"
20 #include "solarus/core/QuestFiles.h"
21 #include "solarus/graphics/Surface.h"
22 #include <utility>
23
24 namespace Solarus {
25
26 bool FontResource::fonts_loaded = false;
27 std::map<std::string, FontResource::FontFile> FontResource::fonts;
28
29 /**
30 * \brief Initializes the font system.
31 */
initialize()32 void FontResource::initialize() {
33
34 TTF_Init();
35 }
36
37 /**
38 * \brief Closes the font system.
39 */
quit()40 void FontResource::quit() {
41
42 fonts.clear();
43 fonts_loaded = false;
44 TTF_Quit();
45 }
46
47 /**
48 * \brief Loads the fonts declared in the quest resource list.
49 */
load_fonts()50 void FontResource::load_fonts() {
51
52 // Get the list of available fonts.
53 const std::map<std::string, std::string>& font_resource =
54 CurrentQuest::get_resources(ResourceType::FONT);
55
56 for (const auto& kvp: font_resource) {
57
58 const std::string& font_id = kvp.first;
59
60 FontFile font;
61
62 // Load the font.
63
64 bool bitmap_font = false;
65 const std::string file_name_start = std::string("fonts/") + font_id;
66 if (QuestFiles::data_file_exists(file_name_start + ".png")) {
67 font.file_name = file_name_start + ".png";
68 bitmap_font = true;
69 }
70 else if (QuestFiles::data_file_exists(file_name_start + ".PNG")) {
71 font.file_name = file_name_start + ".PNG";
72 bitmap_font = true;
73 }
74 else if (QuestFiles::data_file_exists(file_name_start + ".ttf")) {
75 font.file_name = file_name_start + ".ttf";
76 }
77 else if (QuestFiles::data_file_exists(file_name_start + ".TTF")) {
78 font.file_name = file_name_start + ".TTF";
79 }
80 else if (QuestFiles::data_file_exists(file_name_start + ".otf")) {
81 font.file_name = file_name_start + ".otf";
82 }
83 else if (QuestFiles::data_file_exists(file_name_start + ".OTF")) {
84 font.file_name = file_name_start + ".OTF";
85 }
86 else if (QuestFiles::data_file_exists(file_name_start + ".ttc")) {
87 font.file_name = file_name_start + ".ttc";
88 }
89 else if (QuestFiles::data_file_exists(file_name_start + ".TTC")) {
90 font.file_name = file_name_start + ".TTC";
91 }
92 else if (QuestFiles::data_file_exists(file_name_start + ".fon")) {
93 font.file_name = file_name_start + ".fon";
94 }
95 else if (QuestFiles::data_file_exists(file_name_start + ".FON")) {
96 font.file_name = file_name_start + ".FON";
97 }
98 else {
99 Debug::error(std::string("Cannot find font file 'fonts/")
100 + font_id + "' (tried with extensions .png, .ttf, .otf, .ttc and .fon)"
101 );
102 continue;
103 }
104
105 if (bitmap_font) {
106 // It's a bitmap font.
107 font.bitmap_font = Surface::create(font.file_name, Surface::DIR_DATA);
108 }
109
110 else {
111 // It's an outline font.
112 font.buffer = QuestFiles::data_file_read(font.file_name);
113 font.bitmap_font = nullptr;
114 }
115
116 fonts.emplace(font_id, std::move(font));
117 }
118
119 fonts_loaded = true;
120 }
121
122 /**
123 * \brief Returns the id of default font.
124 * \return Id of the first font in alphabetical order, or an empty string
125 * if there is no font at all.
126 */
get_default_font_id()127 std::string FontResource::get_default_font_id() {
128
129 if (!fonts_loaded) {
130 load_fonts();
131 }
132
133 if (fonts.empty()) {
134 return "";
135 }
136
137 return fonts.begin()->first;
138 }
139
140 /**
141 * \brief Returns whether the specified font exists.
142 * \param font_id The id to test.
143 * \return \c true if there is a valid font with this id in the quest resource
144 * list.
145 */
exists(const std::string & font_id)146 bool FontResource::exists(const std::string& font_id) {
147
148 if (!fonts_loaded) {
149 load_fonts();
150 }
151
152 return fonts.find(font_id) != fonts.end();
153 }
154
155 /**
156 * \brief Returns whether the specified font is a bitmap or an outline font.
157 * \param font_id Id of the font to test. It must exist.
158 * \return \c true if this is a bitmap font, \c false if this is an outline font.
159 */
is_bitmap_font(const std::string & font_id)160 bool FontResource::is_bitmap_font(const std::string& font_id) {
161
162 if (!fonts_loaded) {
163 load_fonts();
164 }
165
166 const auto& kvp = fonts.find(font_id);
167 Debug::check_assertion(kvp != fonts.end(), std::string("No such font: '") + font_id + "'");
168 return kvp->second.bitmap_font != nullptr;
169 }
170
171 /**
172 * \brief Returns the surface image of a bitmap font.
173 * \param font_id Id of the bitmap font to get. It must exist.
174 * \return The bitmap.
175 */
get_bitmap_font(const std::string & font_id)176 SurfacePtr FontResource::get_bitmap_font(const std::string& font_id) {
177
178 if (!fonts_loaded) {
179 load_fonts();
180 }
181
182 const auto& kvp = fonts.find(font_id);
183 Debug::check_assertion(kvp != fonts.end(), std::string("No such font: '") + font_id + "'");
184 Debug::check_assertion(kvp->second.bitmap_font != nullptr, std::string("This is not a bitmap font: '") + font_id + "'");
185 return kvp->second.bitmap_font;
186 }
187
188 /**
189 * \brief Returns an outline font with the specified size.
190 * \param font_id Id of the outline font to get. It must exist.
191 * \param size Size to use.
192 * \return The font.
193 */
get_outline_font(const std::string & font_id,int size)194 TTF_Font& FontResource::get_outline_font(const std::string& font_id, int size) {
195
196 if (!fonts_loaded) {
197 load_fonts();
198 }
199
200 const auto& kvp = fonts.find(font_id);
201 Debug::check_assertion(kvp != fonts.end(), std::string("No such font: '") + font_id + "'");
202 FontFile& font = kvp->second;
203 Debug::check_assertion(font.bitmap_font == nullptr, std::string("This is not an outline font: '") + font_id + "'");
204
205 std::map<int, OutlineFontReader>& outline_fonts = kvp->second.outline_fonts;
206
207 const auto& kvp2 = outline_fonts.find(size);
208 if (kvp2 != outline_fonts.end()) {
209 return *kvp2->second.outline_font;
210 }
211
212 // First time we want this font with this particular size.
213 SDL_RWops_UniquePtr rw = SDL_RWops_UniquePtr(SDL_RWFromMem(
214 const_cast<char*>(font.buffer.data()),
215 (int) font.buffer.size()
216 ));
217 TTF_Font_UniquePtr outline_font(TTF_OpenFontRW(rw.get(), 0, size));
218 Debug::check_assertion(outline_font != nullptr,
219 std::string("Cannot load font from file '") + font.file_name
220 + "': " + TTF_GetError()
221 );
222 OutlineFontReader reader = { std::move(rw), std::move(outline_font) };
223 outline_fonts.emplace(size, std::move(reader));
224 return *outline_fonts.at(size).outline_font;
225 }
226
227 }
228
229